Skip to content

dash_charts.app_px⚓︎

Generic Plotly Express Data Analysis App(s).

Examples: https://www.plotly.express/

Docs: https://www.plotly.express/plotly_express/

(Currently) Unsupported plotly express types⚓︎

px.parallel_coordinates(px.data.iris(), color="species_id",
                        dimensions=['sepal_width', 'sepal_length', 'petal_width', 'petal_length'])
px.treemap(px.data.tips(), path=['day', 'time', 'sex'], values='total_bill')
px.sunburst(px.data.tips(), path=['day', 'time', 'sex'], values='total_bill)

Other charts that could be useful (but won’t work with simple dropdowns)

  • scatter_matrix([data_frame, dimensions, …])
    • In a scatter plot matrix (or SPLOM), each row of data_frame is
    • https://plotly.com/python/splom/
  • parallel_coordinates([data_frame, …])
    • In a parallel coordinates plot, each row of data_frame is represented
    • https://plotly.com/python-api-reference/generated/plotly.express.parallel_coordinates.html
  • parallel_categories([data_frame, …])
    • In a parallel categories (or parallel sets) plot, each row of
    • https://plotly.com/python-api-reference/generated/plotly.express.parallel_categories.html
  • density_heatmap([data_frame, x, y, z, …])
    • In a density heatmap, rows of data_frame are grouped together into
    • https://plotly.com/python-api-reference/generated/plotly.express.density_heatmap.html
  • imshow(img[, zmin, zmax, origin, …])
    • Display an image, i.e.
    • https://plotly.com/python/imshow/
View Source
"""Generic Plotly Express Data Analysis App(s).

Examples: https://www.plotly.express/

Docs: https://www.plotly.express/plotly_express/

# (Currently) Unsupported plotly express types

```py
px.parallel_coordinates(px.data.iris(), color="species_id",
                        dimensions=['sepal_width', 'sepal_length', 'petal_width', 'petal_length'])
px.treemap(px.data.tips(), path=['day', 'time', 'sex'], values='total_bill')
px.sunburst(px.data.tips(), path=['day', 'time', 'sex'], values='total_bill)

Other charts that could be useful (but won’t work with simple dropdowns)

  • scatter_matrix([data_frame, dimensions, …])
    • In a scatter plot matrix (or SPLOM), each row of data_frame is
    • https://plotly.com/python/splom/
  • parallel_coordinates([data_frame, …])
    • In a parallel coordinates plot, each row of data_frame is represented
    • https://plotly.com/python-api-reference/generated/plotly.express.parallel_coordinates.html
  • parallel_categories([data_frame, …])
    • In a parallel categories (or parallel sets) plot, each row of
    • https://plotly.com/python-api-reference/generated/plotly.express.parallel_categories.html
  • density_heatmap([data_frame, x, y, z, …])
    • In a density heatmap, rows of data_frame are grouped together into
    • https://plotly.com/python-api-reference/generated/plotly.express.density_heatmap.html
  • imshow(img[, zmin, zmax, origin, …])
    • Display an image, i.e.
    • https://plotly.com/python/imshow/

”“”

from collections import OrderedDict

import dash import dash_bootstrap_components as dbc import pandas as pd import plotly.express as px from dash import html from implements import implements

from .components import dropdown_group, opts_dd from .utils_app import AppBase, AppInterface from .utils_app_with_navigation import FullScreenAppWithTabs from .utils_callbacks import map_args, map_outputs from .utils_fig import min_graph

======================================================================================================================⚓︎

Create classes to manage tabs state. Easy to scale up or down⚓︎

>> Demo uses sample data. User could replace with data loaded from a static CSV file, TinyDB, SQLite, etc.⚓︎

@implements(AppInterface) # noqa: H601 class TabBase(AppBase): “”“Base tab class with helper methods.”“”

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
external_stylesheets = [dbc.themes.FLATLY]

# ID Elements for UI
id_chart: str = 'chart'
id_func: str = 'func'
id_template: str = 'template'  # PLANNED: template should be able to be None

takes_args: bool = True
"""If True, will pass arguments from UI to function."""

templates: list = [
    'ggplot2', 'seaborn', 'simple_white', 'plotly',
    'plotly_white', 'plotly_dark', 'presentation', 'xgridoff',
    'ygridoff', 'gridon', 'none',
]
"""List of templates from: `import plotly.io as pio; pio.templates`"""

# Must override in child class
name: str = None
"""Unique tab component name. Must be overridden in child class."""
data: pd.DataFrame = None
"""Dataframe. Must be overridden in child class."""
func_map: OrderedDict = None
"""Map of functions to keywords. Must be overridden in child class."""

# PLANNED: below items should be able to be None
dims: tuple = ()
"""Keyword from function for dropdowns with column names as options. Must be overridden in child class."""
dims_dict: OrderedDict = OrderedDict([])
"""OrderedDict of keyword from function to allowed values. Must be overridden in child class."""
default_dim_name = {}
"""Lookup for dim:column name to use as default in dropdown."""

def initialization(self) -> None:
    """Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
    super().initialization()

    # Register the the unique element IDs
    self.input_ids = [self.id_func, self.id_template] + [*self.dims] + [*self.dims_dict.keys()]
    self.register_uniq_ids([self.id_chart] + self.input_ids)

    # Configure the options for the various dropdowns
    self.col_opts = [] if self.data is None else tuple(opts_dd(_c, _c) for _c in self.data.columns)
    self.func_opts = tuple(opts_dd(lbl, lbl) for lbl in self.func_map.keys())
    self.t_opts = tuple(opts_dd(template, template) for template in self.templates)

def create_elements(self) -> None:
    """Initialize the charts, tables, and other Dash elements."""
    ...

def verify_types_for_layout(self):
    """Verify data types of data members necessary for the layout of this tab.

    Raises:
        RuntimeError: if any relevant data members are of the wrong type

    """
    errors = []
    if not isinstance(self.name, str):
        errors.append(f'Expected self.name="{self.name}" to be str')
    if not isinstance(self.dims, tuple):
        errors.append(f'Expected self.dims="{self.dims}" to be tuple')
    if not isinstance(self.dims_dict, OrderedDict):
        errors.append(f'Expected self.dims_dict="{self.dims_dict}" to be OrderedDict')
    if errors:
        formatted_errors = '\n' + '\n'.join(errors)
        raise RuntimeError(f'Found errors in data members:{formatted_errors}')

def verify_types_for_callbacks(self):
    """Verify data types of data members necessary for the callbacks of this tab.

    Raises:
        RuntimeError: if any relevant data members are of the wrong type

    """
    errors = []
    if not isinstance(self.takes_args, bool):
        errors.append(f'Expected self.takes_args="{self.takes_args}" to be bool')
    if not (isinstance(self.data, pd.DataFrame) or self.data is None):
        errors.append(f'Expected self.data="{self.data}" to be pd.DataFrame or None')
    if not isinstance(self.func_map, OrderedDict):
        errors.append(f'Expected self.func_map="{self.func_map}" to be OrderedDict')
    if errors:
        formatted_errors = '\n' + '\n'.join(errors)
        raise RuntimeError(f'Found errors in data members:{formatted_errors}')

def return_layout(self) -> dict:
    """Return Dash application layout.

    Returns:
        dict: Dash HTML object

    """
    self.verify_types_for_layout()

    return html.Div(
        [  # noqa: ECE001
            html.Div(
                [
                    dropdown_group(
                        'Plot Type:', self._il[self.id_func],
                        self.func_opts, value=self.func_opts[0]['label'],
                    ),
                    dropdown_group(
                        'Template:', self._il[self.id_template],
                        self.t_opts, value=self.t_opts[0]['label'],
                    ),
                ] + [
                    dropdown_group(
                        f'{dim}:', self._il[dim], self.col_opts,
                        value=self.default_dim_name.get(dim, None),
                    )
                    for dim in self.dims
                ] + [
                    dropdown_group(f'{dim}:', self._il[dim], [opts_dd(item, item) for item in items])
                    for dim, items in self.dims_dict.items()
                ], style={'width': '25%', 'float': 'left'},
            ),
            min_graph(id=self._il[self.id_chart], style={'width': '75%', 'display': 'inline-block'}),
        ], style={'padding': '15px'},
    )

def create_callbacks(self) -> None:
    """Register callbacks necessary for this tab."""
    self.verify_types_for_callbacks()

    self.register_update_chart()

def register_update_chart(self):   # noqa: CCR001
    """Register the update_chart callback."""
    outputs = [(self.id_chart, 'figure')]
    inputs = [(_id, 'value') for _id in self.input_ids]
    states = ()

    @self.callback(outputs, inputs, states)
    def update_chart(*raw_args):
        a_in, _a_states = map_args(raw_args, inputs, states)
        name_func = a_in[self.id_func]['value']

        properties = [trigger['prop_id'] for trigger in dash.callback_context.triggered]
        new_chart = {}
        # If event is not a tab change, return the updated chart
        if 'tabs-select.value' not in properties:  # FIXME: replace tabs-select with actual keyname (?)
            if self.takes_args:
                # Parse the arguments to generate a new plot
                kwargs = {key: a_in[key]['value'] for key in self.input_ids[1:]}
                new_chart = self.func_map[name_func](self.data, height=650, **kwargs)
            else:
                new_chart = self.func_map[name_func]()
        # Example Mapping Output. Alternatively, just: `return [new_chart]`
        return map_outputs(outputs, [(self.id_chart, 'figure', new_chart)])

@implements(AppInterface) # noqa: H601 class TabTip(TabBase): “”“TabTip properties.”“”

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
name = 'Tip Data'
data = px.data.tips()
func_map = OrderedDict([
    ('scatter', px.scatter),
    ('density_contour', px.density_contour),
])
dims = ('x', 'y', 'color', 'facet_row', 'facet_col')
dims_dict = OrderedDict([
    ('marginal_x', ('histogram', 'rag', 'violin', 'box')),
    ('marginal_y', ('histogram', 'rag', 'violin', 'box')),
    ('trendline', ('ols', 'lowess')),
])
default_dim_name = {
    'x': 'total_bill',
    'y': 'tip',
    'color': 'smoker',
}

@implements(AppInterface) # noqa: H601 class TabIris(TabBase): “”“TabIris properties.”“”

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
name = 'Iris Data'
data = px.data.iris()
func_map = OrderedDict([
    ('histogram', px.histogram),
    ('bar', px.bar),
    ('strip', px.strip),
    ('box', px.box),
    ('violin', px.violin),
])
dims = ('x', 'y', 'color', 'facet_row', 'facet_col')
default_dim_name = {
    'x': 'sepal_width',
    'color': 'species',
}

@implements(AppInterface) # noqa: H601 class TabGapminder(TabBase): “”“TabGapminder properties.”“”

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
name = 'Gapminder Data'
data = px.data.gapminder()
func_map = OrderedDict([
    ('area', px.area),
    ('line', px.line),
])
dims = ('x', 'y', 'color', 'line_group', 'facet_row', 'facet_col')
default_dim_name = {
    'x': 'year',
    'y': 'pop',
    'color': 'continent',
    'line_group': 'country',
}

@implements(AppInterface) # noqa: H601 class TabTernary(TabBase): “”“TabTernary properties.”“”

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
name = 'Ternary'
data = px.data.election()
func_map = OrderedDict([
    ('scatter_ternary', px.scatter_ternary),
    ('line_ternary', px.line_ternary),
])
dims = ('a', 'b', 'c', 'color', 'hover_name')  # size - only for scatter
default_dim_name = {
    'a': 'Joly',
    'b': 'Coderre',
    'c': 'Bergeron',
    'color': 'winner',
    'hover_name': 'district',
}

@implements(AppInterface) # noqa: H601 class TabWind(TabBase): “”“TabWind properties.”“”

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
name = 'Wind'
data = px.data.wind()
func_map = OrderedDict([
    ('scatter_polar', px.scatter_polar),
    ('line_polar', px.line_polar),  # (line_close=True)
    ('bar_polar', px.bar_polar),
])
dims = ('r', 'theta', 'color')
default_dim_name = {
    'r': 'frequency',
    'theta': 'direction',
    'color': 'strength',
    'symbol': 'strength',
}

@implements(AppInterface) # noqa: H601 class TabColor(TabBase): “”“TabColor properties.”“”

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
name = 'Color Swatches'
takes_args = False
func_map = OrderedDict([
    ('colors.qualitative', px.colors.qualitative.swatches),
    ('colors.sequential', px.colors.sequential.swatches),
    ('colors.diverging', px.colors.diverging.swatches),
    ('colors.cyclical', px.colors.cyclical.swatches),
    ('colors.colorbrewer', px.colors.colorbrewer.swatches),
    ('colors.cmocean', px.colors.cmocean.swatches),
    ('colors.carto', px.colors.carto.swatches),
])
default_dim_name = {
    'x': 'sepal_width',
    'y': 'sepal_length',
}

======================================================================================================================⚓︎

Create class for application to control manage variable scopes⚓︎

class InteractivePXApp(FullScreenAppWithTabs): # noqa: H601 “”“Plotly Express Demo application.”“”

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
name = 'TabAppDemo'

tabs_location = 'right'
"""Tab orientation setting. One of `(left, top, bottom, right)`."""

tabs_margin = '175px'
"""Adjust this setting based on the width or height of the tabs to prevent the content from overlapping the tabs."""

tabs_compact = False
"""Boolean setting to toggle between a padded tab layout if False and a minimal compact version if True."""

def define_nav_elements(self):
    """Return list of initialized tabs.

    Returns:
        list: each item is an initialized tab (ex `[AppBase(self.app)]` in the order each tab is rendered

    """
    return [
        TabTip(app=self.app),
        TabIris(app=self.app),
        TabGapminder(app=self.app),
        TabTernary(app=self.app),
        TabWind(app=self.app),
        TabColor(app=self.app),
    ]

def return_layout(self) -> dict:
    """Return Dash application layout.

    Returns:
        dict: Dash HTML object

    """
    return html.Div([
        html.H1('Dash/Plotly Express Data Exploration Demo', style={'padding': '15px 0 0 15px'}),
        super().return_layout(),
    ])

```

Classes⚓︎

InteractivePXApp⚓︎

class InteractivePXApp(
    app: Union[dash.dash.Dash, NoneType] = None
)
View Source
class InteractivePXApp(FullScreenAppWithTabs):  # noqa: H601
    """Plotly Express Demo application."""

    name = 'TabAppDemo'

    tabs_location = 'right'
    """Tab orientation setting. One of `(left, top, bottom, right)`."""

    tabs_margin = '175px'
    """Adjust this setting based on the width or height of the tabs to prevent the content from overlapping the tabs."""

    tabs_compact = False
    """Boolean setting to toggle between a padded tab layout if False and a minimal compact version if True."""

    def define_nav_elements(self):
        """Return list of initialized tabs.

        Returns:
            list: each item is an initialized tab (ex `[AppBase(self.app)]` in the order each tab is rendered

        """
        return [
            TabTip(app=self.app),
            TabIris(app=self.app),
            TabGapminder(app=self.app),
            TabTernary(app=self.app),
            TabWind(app=self.app),
            TabColor(app=self.app),
        ]

    def return_layout(self) -> dict:
        """Return Dash application layout.

        Returns:
            dict: Dash HTML object

        """
        return html.Div([
            html.H1('Dash/Plotly Express Data Exploration Demo', style={'padding': '15px 0 0 15px'}),
            super().return_layout(),
        ])

Ancestors (in MRO)⚓︎

  • dash_charts.utils_app_with_navigation.FullScreenAppWithTabs
  • dash_charts.utils_app_with_navigation.AppWithTabs
  • dash_charts.utils_app_with_navigation.AppWithNavigation
  • dash_charts.utils_app.AppBase

Class variables⚓︎

app
app_ids
external_stylesheets
id_tabs_content
id_tabs_select
init_app_kwargs
modules
name
nav_layouts
nav_lookup
nsi
tabs_compact

Boolean setting to toggle between a padded tab layout if False and a minimal compact version if True.

tabs_location

Tab orientation setting. One of (left, top, bottom, right).

tabs_margin

Adjust this setting based on the width or height of the tabs to prevent the content from overlapping the tabs.

validation_layout

Methods⚓︎

callback⚓︎

def callback(
    self,
    outputs,
    inputs,
    states,
    pic: bool = False,
    **kwargs: dict
)

Return app callback decorator based on provided components.

Parameters:

Name Description
outputs list of tuples with app_id and property name
inputs list of tuples with app_id and property name
states list of tuples with app_id and property name
pic If True, prevent call on page load (prevent_initial_call). Default is False
**kwargs any additional keyword arguments for self.app.callback

Returns:

Type Description
dict result of self.app.callback()
View Source
    def callback(self, outputs, inputs, states, pic: bool = False, **kwargs: dict):
        """Return app callback decorator based on provided components.

        Args:
            outputs: list of tuples with app_id and property name
            inputs: list of tuples with app_id and property name
            states: list of tuples with app_id and property name
            pic: If True, prevent call on page load (`prevent_initial_call`). Default is False
            **kwargs: any additional keyword arguments for `self.app.callback`

        Returns:
            dict: result of `self.app.callback()`

        """
        return self.app.callback(
            *format_app_callback(self._il, outputs, inputs, states),
            prevent_initial_call=pic,
            **kwargs,
        )

create⚓︎

def create(
    self,
    **kwargs
)

Create each navigation componet, storing the layout. Then parent class to create application.

Parameters:

Name Description
kwargs keyword arguments passed to self.create
View Source
    def create(self, **kwargs):
        """Create each navigation componet, storing the layout. Then parent class to create application.

        Args:
            kwargs: keyword arguments passed to `self.create`

        """
        # Initialize the lookup for each tab then configure each tab
        self.nav_lookup = OrderedDict([(tab.name, tab) for tab in self.define_nav_elements()])
        self.nav_layouts = {}
        for nav_name, nav in self.nav_lookup.items():
            nav.create(assign_layout=False)
            self.nav_layouts[nav_name] = nav.return_layout()

        # Store validation_layout that is later used for callback verification in base class
        self.validation_layout = [*map(deepcopy, self.nav_layouts.values())]

        # Initialize parent application that handles navigation
        super().create(**kwargs)

create_callbacks⚓︎

def create_callbacks(
    self
) -> None

Register the navigation callback.

View Source
    def create_callbacks(self) -> None:
        """Register the navigation callback."""
        outputs = [(self.id_tabs_content, 'children')]
        inputs = [(self.id_tabs_select, 'value')]

        @self.callback(outputs, inputs, [])
        def render_tab(tab_name):
            return [self.nav_layouts[tab_name]]

create_elements⚓︎

def create_elements(
    self
) -> None

Override method as not needed at navigation-level.

View Source
    def create_elements(self) -> None:
        """Override method as not needed at navigation-level."""
        ...  # pragma: no cover

define_nav_elements⚓︎

def define_nav_elements(
    self
)

Return list of initialized tabs.

Returns:

Type Description
list each item is an initialized tab (ex [AppBase(self.app)] in the order each tab is rendered
View Source
    def define_nav_elements(self):
        """Return list of initialized tabs.

        Returns:
            list: each item is an initialized tab (ex `[AppBase(self.app)]` in the order each tab is rendered

        """
        return [
            TabTip(app=self.app),
            TabIris(app=self.app),
            TabGapminder(app=self.app),
            TabTernary(app=self.app),
            TabWind(app=self.app),
            TabColor(app=self.app),
        ]

generate_data⚓︎

def generate_data(
    self
) -> None

Recommended method for generating data stored in memory. Called in initialization.

View Source
    def generate_data(self) -> None:
        """Recommended method for generating data stored in memory. Called in initialization."""
        ...

generate_tab_kwargs⚓︎

def generate_tab_kwargs(
    self
)

Create the tab keyword arguments. Intended to be modified through inheritance.

Returns:

Type Description
tuple keyword arguments and styling for the dcc.Tab elements
- tab_kwargs: with at minimum keys (style, selected_style) for dcc.Tab
- tabs_kwargs: to be passed to dcc.Tabs
- tabs_style: style for the dcc.Tabs HTML element
View Source
    def generate_tab_kwargs(self):
        """Create the tab keyword arguments. Intended to be modified through inheritance.

        Returns:
            tuple: keyword arguments and styling for the dcc.Tab elements

                - tab_kwargs: with at minimum keys `(style, selected_style)` for dcc.Tab
                - tabs_kwargs: to be passed to dcc.Tabs
                - tabs_style: style for the dcc.Tabs HTML element

        """
        # Unselected tab style
        if self.tabs_compact:
            tab_style = {'padding': '2px 4px 2px 4px'}
            tabs_padding = '6px 0 0 2px'
        else:
            tab_style = {'padding': '10px 20px 10px 20px'}
            tabs_padding = '15px 0 0 5px'
        # Extend tab style for selected case
        selected_style = deepcopy(tab_style)
        opposite_lookup = {'top': 'bottom', 'bottom': 'top', 'left': 'right', 'right': 'left'}
        tabs_style = {   # noqa: ECE001
            'backgroundColor': '#F9F9F9',
            'padding': tabs_padding,
            'position': 'fixed',
            'zIndex': '999',
            f'border{opposite_lookup[self.tabs_location].title()}': '1px solid #d6d6d6',
            self.tabs_location: '0',
        }
        if self.tabs_location in ['left', 'right']:
            # Configure for vertical case
            selected_style['border-left'] = '3px solid #119DFF'
            tabs_kwargs = {
                'vertical': True,
                'style': {'width': '100%'},
                'parent_style': {'width': '100%'},
            }
            tabs_style['top'] = '0'
            tabs_style['bottom'] = '0'
            tabs_style['width'] = 'auto'
        else:
            # Configure for horizontal case
            selected_style['border-top'] = '3px solid #119DFF'
            tabs_kwargs = {}
            tabs_style['height'] = 'auto'
            tabs_style['right'] = '0'
            tabs_style['left'] = '0'

        tab_kwargs = {'style': tab_style, 'selected_style': selected_style}
        return (tab_kwargs, tabs_kwargs, tabs_style)

get_server⚓︎

def get_server(
    self
)

Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

Returns:

Type Description
dict the Flask server component of the Dash app
View Source
    def get_server(self):
        """Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

        Returns:
            dict: the Flask `server` component of the Dash app

        """
        return self.app.server

initialization⚓︎

def initialization(
    self
) -> None

Initialize ids with self.register_uniq_ids([...]) and other one-time actions.

View Source
    def initialization(self) -> None:
        """Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
        super().initialization()
        self.register_uniq_ids(self.app_ids)

override_module_defaults⚓︎

def override_module_defaults(
    self
) -> None

Override default values from modules.

View Source
    def override_module_defaults(self) -> None:
        """Override default values from modules."""
        ...

register_uniq_ids⚓︎

def register_uniq_ids(
    self,
    app_ids: List[str]
) -> None

Register the app_ids to the corresponding global_id in the self._il lookup dictionary.

The app_ids must be unique within this App so that a layout can be created. This method registers self._il which are a list of globally unique ids (incorporating this App’s unique self.name) allowing for the child class of this base App to be resused multiple times within a tabbed or multi-page application without id-collision

Parameters:

Name Description
app_ids list of strings that are unique within this App
View Source
    def register_uniq_ids(self, app_ids: List[str]) -> None:
        """Register the `app_ids` to the corresponding global_id in the `self._il` lookup dictionary.

        The app_ids must be unique within this App so that a layout can be created. This method registers `self._il`
          which are a list of globally unique ids (incorporating this App's unique `self.name`) allowing for the child
          class of this base App to be resused multiple times within a tabbed or multi-page application without
          id-collision

        Args:
            app_ids: list of strings that are unique within this App

        """
        self._il = deepcopy(self._il)
        for app_id in app_ids:
            self._il[app_id] = f'{self.name}-{app_id}'.replace(' ', '-')

return_layout⚓︎

def return_layout(
    self
) -> dict

Return Dash application layout.

Returns:

Type Description
dict Dash HTML object
View Source
    def return_layout(self) -> dict:
        """Return Dash application layout.

        Returns:
            dict: Dash HTML object

        """
        return html.Div([
            html.H1('Dash/Plotly Express Data Exploration Demo', style={'padding': '15px 0 0 15px'}),
            super().return_layout(),
        ])

run⚓︎

def run(
    self,
    **dash_kwargs: dict
) -> None

Launch the Dash server instance.

Parameters:

Name Description
**dash_kwargs keyword arguments for Dash.run_server()
View Source
    def run(self, **dash_kwargs: dict) -> None:
        """Launch the Dash server instance.

        Args:
            **dash_kwargs: keyword arguments for `Dash.run_server()`

        """
        self.app.run_server(**dash_kwargs)  # pragma: no cover

tab_menu⚓︎

def tab_menu(
    self
)

Return the HTML elements for the tab menu.

Returns:

Type Description
dict Dash HTML object
View Source
    def tab_menu(self):
        """Return the HTML elements for the tab menu.

        Returns:
            dict: Dash HTML object

        """
        tab_kwargs, tabs_kwargs, tabs_style = self.generate_tab_kwargs()
        tabs = [dcc.Tab(label=name, value=name, **tab_kwargs) for name, tab in self.nav_lookup.items()]
        return html.Div(
            children=[
                dcc.Tabs(
                    id=self._il[self.id_tabs_select], value=list(self.nav_lookup.keys())[0],
                    children=tabs, **tabs_kwargs,
                ),
            ], style=tabs_style,
        )

verify_app_initialization⚓︎

def verify_app_initialization(
    self
)

Check that the app was properly initialized.

Raises:

Type Description
RuntimeError if child class has not called self.register_uniq_ids
View Source
    def verify_app_initialization(self):
        """Check that the app was properly initialized.

        Raises:
            RuntimeError: if child class has not called `self.register_uniq_ids`

        """
        super().verify_app_initialization()
        allowed_locations = ('left', 'top', 'bottom', 'right')
        if self.tabs_location not in allowed_locations:  # pragma: no cover
            raise RuntimeError(f'`self.tabs_location = {self.tabs_location}` is not in {allowed_locations}')

TabBase⚓︎

class TabBase(
    app: Union[dash.dash.Dash, NoneType] = None
)
View Source
class TabBase(AppBase):
    """Base tab class with helper methods."""

    external_stylesheets = [dbc.themes.FLATLY]

    # ID Elements for UI
    id_chart: str = 'chart'
    id_func: str = 'func'
    id_template: str = 'template'  # PLANNED: template should be able to be None

    takes_args: bool = True
    """If True, will pass arguments from UI to function."""

    templates: list = [
        'ggplot2', 'seaborn', 'simple_white', 'plotly',
        'plotly_white', 'plotly_dark', 'presentation', 'xgridoff',
        'ygridoff', 'gridon', 'none',
    ]
    """List of templates from: `import plotly.io as pio; pio.templates`"""

    # Must override in child class
    name: str = None
    """Unique tab component name. Must be overridden in child class."""
    data: pd.DataFrame = None
    """Dataframe. Must be overridden in child class."""
    func_map: OrderedDict = None
    """Map of functions to keywords. Must be overridden in child class."""

    # PLANNED: below items should be able to be None
    dims: tuple = ()
    """Keyword from function for dropdowns with column names as options. Must be overridden in child class."""
    dims_dict: OrderedDict = OrderedDict([])
    """OrderedDict of keyword from function to allowed values. Must be overridden in child class."""
    default_dim_name = {}
    """Lookup for dim:column name to use as default in dropdown."""

    def initialization(self) -> None:
        """Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
        super().initialization()

        # Register the the unique element IDs
        self.input_ids = [self.id_func, self.id_template] + [*self.dims] + [*self.dims_dict.keys()]
        self.register_uniq_ids([self.id_chart] + self.input_ids)

        # Configure the options for the various dropdowns
        self.col_opts = [] if self.data is None else tuple(opts_dd(_c, _c) for _c in self.data.columns)
        self.func_opts = tuple(opts_dd(lbl, lbl) for lbl in self.func_map.keys())
        self.t_opts = tuple(opts_dd(template, template) for template in self.templates)

    def create_elements(self) -> None:
        """Initialize the charts, tables, and other Dash elements."""
        ...

    def verify_types_for_layout(self):
        """Verify data types of data members necessary for the layout of this tab.

        Raises:
            RuntimeError: if any relevant data members are of the wrong type

        """
        errors = []
        if not isinstance(self.name, str):
            errors.append(f'Expected self.name="{self.name}" to be str')
        if not isinstance(self.dims, tuple):
            errors.append(f'Expected self.dims="{self.dims}" to be tuple')
        if not isinstance(self.dims_dict, OrderedDict):
            errors.append(f'Expected self.dims_dict="{self.dims_dict}" to be OrderedDict')
        if errors:
            formatted_errors = '\n' + '\n'.join(errors)
            raise RuntimeError(f'Found errors in data members:{formatted_errors}')

    def verify_types_for_callbacks(self):
        """Verify data types of data members necessary for the callbacks of this tab.

        Raises:
            RuntimeError: if any relevant data members are of the wrong type

        """
        errors = []
        if not isinstance(self.takes_args, bool):
            errors.append(f'Expected self.takes_args="{self.takes_args}" to be bool')
        if not (isinstance(self.data, pd.DataFrame) or self.data is None):
            errors.append(f'Expected self.data="{self.data}" to be pd.DataFrame or None')
        if not isinstance(self.func_map, OrderedDict):
            errors.append(f'Expected self.func_map="{self.func_map}" to be OrderedDict')
        if errors:
            formatted_errors = '\n' + '\n'.join(errors)
            raise RuntimeError(f'Found errors in data members:{formatted_errors}')

    def return_layout(self) -> dict:
        """Return Dash application layout.

        Returns:
            dict: Dash HTML object

        """
        self.verify_types_for_layout()

        return html.Div(
            [  # noqa: ECE001
                html.Div(
                    [
                        dropdown_group(
                            'Plot Type:', self._il[self.id_func],
                            self.func_opts, value=self.func_opts[0]['label'],
                        ),
                        dropdown_group(
                            'Template:', self._il[self.id_template],
                            self.t_opts, value=self.t_opts[0]['label'],
                        ),
                    ] + [
                        dropdown_group(
                            f'{dim}:', self._il[dim], self.col_opts,
                            value=self.default_dim_name.get(dim, None),
                        )
                        for dim in self.dims
                    ] + [
                        dropdown_group(f'{dim}:', self._il[dim], [opts_dd(item, item) for item in items])
                        for dim, items in self.dims_dict.items()
                    ], style={'width': '25%', 'float': 'left'},
                ),
                min_graph(id=self._il[self.id_chart], style={'width': '75%', 'display': 'inline-block'}),
            ], style={'padding': '15px'},
        )

    def create_callbacks(self) -> None:
        """Register callbacks necessary for this tab."""
        self.verify_types_for_callbacks()

        self.register_update_chart()

    def register_update_chart(self):   # noqa: CCR001
        """Register the update_chart callback."""
        outputs = [(self.id_chart, 'figure')]
        inputs = [(_id, 'value') for _id in self.input_ids]
        states = ()

        @self.callback(outputs, inputs, states)
        def update_chart(*raw_args):
            a_in, _a_states = map_args(raw_args, inputs, states)
            name_func = a_in[self.id_func]['value']

            properties = [trigger['prop_id'] for trigger in dash.callback_context.triggered]
            new_chart = {}
            # If event is not a tab change, return the updated chart
            if 'tabs-select.value' not in properties:  # FIXME: replace tabs-select with actual keyname (?)
                if self.takes_args:
                    # Parse the arguments to generate a new plot
                    kwargs = {key: a_in[key]['value'] for key in self.input_ids[1:]}
                    new_chart = self.func_map[name_func](self.data, height=650, **kwargs)
                else:
                    new_chart = self.func_map[name_func]()
            # Example Mapping Output. Alternatively, just: `return [new_chart]`
            return map_outputs(outputs, [(self.id_chart, 'figure', new_chart)])

Ancestors (in MRO)⚓︎

  • dash_charts.utils_app.AppBase

Descendants⚓︎

  • dash_charts.app_px.TabTip
  • dash_charts.app_px.TabIris
  • dash_charts.app_px.TabGapminder
  • dash_charts.app_px.TabTernary
  • dash_charts.app_px.TabWind
  • dash_charts.app_px.TabColor

Class variables⚓︎

data
default_dim_name

Lookup for dim:column name to use as default in dropdown.

dims
dims_dict
external_stylesheets
func_map
id_chart
id_func
id_template
init_app_kwargs
modules
name
nsi
takes_args
templates
validation_layout

Methods⚓︎

callback⚓︎

def callback(
    self,
    outputs,
    inputs,
    states,
    pic: bool = False,
    **kwargs: dict
)

Return app callback decorator based on provided components.

Parameters:

Name Description
outputs list of tuples with app_id and property name
inputs list of tuples with app_id and property name
states list of tuples with app_id and property name
pic If True, prevent call on page load (prevent_initial_call). Default is False
**kwargs any additional keyword arguments for self.app.callback

Returns:

Type Description
dict result of self.app.callback()
View Source
    def callback(self, outputs, inputs, states, pic: bool = False, **kwargs: dict):
        """Return app callback decorator based on provided components.

        Args:
            outputs: list of tuples with app_id and property name
            inputs: list of tuples with app_id and property name
            states: list of tuples with app_id and property name
            pic: If True, prevent call on page load (`prevent_initial_call`). Default is False
            **kwargs: any additional keyword arguments for `self.app.callback`

        Returns:
            dict: result of `self.app.callback()`

        """
        return self.app.callback(
            *format_app_callback(self._il, outputs, inputs, states),
            prevent_initial_call=pic,
            **kwargs,
        )

create⚓︎

def create(
    self,
    assign_layout: bool = True
) -> None

Create the ids, app charts, layout, callbacks, and optional modules.

Parameters:

Name Description
assign_layout if True, will assign self.app.layout. If False, must call self.return_layout separately.
Default is True

Raises:

Type Description
NotImplementedError if child class has not set the self.name data member
View Source
    def create(self, assign_layout: bool = True) -> None:  # noqa: CCR001
        """Create the ids, app charts, layout, callbacks, and optional modules.

        Args:
            assign_layout: if True, will assign `self.app.layout`. If False, must call `self.return_layout` separately.
                Default is True

        Raises:
            NotImplementedError: if child class has not set the `self.name` data member

        """
        if self.name is None:  # pragma: no cover
            raise NotImplementedError('Child class must set `self.name` to a unique string for this app')

        # Initialize app and each module
        self.initialization()
        for mod in self.modules:
            self.register_uniq_ids(mod.all_ids)
        self.override_module_defaults()  # Call optional override method

        # Create charts for app and each module
        self.create_elements()
        for mod in self.modules:
            mod.create_elements(self._il)

        # Create app layout. User must call the return_layout method from each module within own return_layout method
        if assign_layout:
            self.app.layout = self.return_layout()
        if assign_layout and self.validation_layout:
            self.app.validation_layout = [deepcopy(self.app.layout)] + self.validation_layout
            pprint('\n\nValidationLayout?')
            pprint(self.app.validation_layout)

        # Create callbacks for app and each module
        self.create_callbacks()
        for mod in self.modules:
            mod.create_callbacks(self)

        self.verify_app_initialization()

create_callbacks⚓︎

def create_callbacks(
    self
) -> None

Register callbacks necessary for this tab.

View Source
    def create_callbacks(self) -> None:
        """Register callbacks necessary for this tab."""
        self.verify_types_for_callbacks()

        self.register_update_chart()

create_elements⚓︎

def create_elements(
    self
) -> None

Initialize the charts, tables, and other Dash elements.

View Source
    def create_elements(self) -> None:
        """Initialize the charts, tables, and other Dash elements."""
        ...

generate_data⚓︎

def generate_data(
    self
) -> None

Recommended method for generating data stored in memory. Called in initialization.

View Source
    def generate_data(self) -> None:
        """Recommended method for generating data stored in memory. Called in initialization."""
        ...

get_server⚓︎

def get_server(
    self
)

Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

Returns:

Type Description
dict the Flask server component of the Dash app
View Source
    def get_server(self):
        """Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

        Returns:
            dict: the Flask `server` component of the Dash app

        """
        return self.app.server

initialization⚓︎

def initialization(
    self
) -> None

Initialize ids with self.register_uniq_ids([...]) and other one-time actions.

View Source
    def initialization(self) -> None:
        """Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
        super().initialization()

        # Register the the unique element IDs
        self.input_ids = [self.id_func, self.id_template] + [*self.dims] + [*self.dims_dict.keys()]
        self.register_uniq_ids([self.id_chart] + self.input_ids)

        # Configure the options for the various dropdowns
        self.col_opts = [] if self.data is None else tuple(opts_dd(_c, _c) for _c in self.data.columns)
        self.func_opts = tuple(opts_dd(lbl, lbl) for lbl in self.func_map.keys())
        self.t_opts = tuple(opts_dd(template, template) for template in self.templates)

override_module_defaults⚓︎

def override_module_defaults(
    self
) -> None

Override default values from modules.

View Source
    def override_module_defaults(self) -> None:
        """Override default values from modules."""
        ...

register_uniq_ids⚓︎

def register_uniq_ids(
    self,
    app_ids: List[str]
) -> None

Register the app_ids to the corresponding global_id in the self._il lookup dictionary.

The app_ids must be unique within this App so that a layout can be created. This method registers self._il which are a list of globally unique ids (incorporating this App’s unique self.name) allowing for the child class of this base App to be resused multiple times within a tabbed or multi-page application without id-collision

Parameters:

Name Description
app_ids list of strings that are unique within this App
View Source
    def register_uniq_ids(self, app_ids: List[str]) -> None:
        """Register the `app_ids` to the corresponding global_id in the `self._il` lookup dictionary.

        The app_ids must be unique within this App so that a layout can be created. This method registers `self._il`
          which are a list of globally unique ids (incorporating this App's unique `self.name`) allowing for the child
          class of this base App to be resused multiple times within a tabbed or multi-page application without
          id-collision

        Args:
            app_ids: list of strings that are unique within this App

        """
        self._il = deepcopy(self._il)
        for app_id in app_ids:
            self._il[app_id] = f'{self.name}-{app_id}'.replace(' ', '-')

register_update_chart⚓︎

def register_update_chart(
    self
)

Register the update_chart callback.

View Source
    def register_update_chart(self):   # noqa: CCR001
        """Register the update_chart callback."""
        outputs = [(self.id_chart, 'figure')]
        inputs = [(_id, 'value') for _id in self.input_ids]
        states = ()

        @self.callback(outputs, inputs, states)
        def update_chart(*raw_args):
            a_in, _a_states = map_args(raw_args, inputs, states)
            name_func = a_in[self.id_func]['value']

            properties = [trigger['prop_id'] for trigger in dash.callback_context.triggered]
            new_chart = {}
            # If event is not a tab change, return the updated chart
            if 'tabs-select.value' not in properties:  # FIXME: replace tabs-select with actual keyname (?)
                if self.takes_args:
                    # Parse the arguments to generate a new plot
                    kwargs = {key: a_in[key]['value'] for key in self.input_ids[1:]}
                    new_chart = self.func_map[name_func](self.data, height=650, **kwargs)
                else:
                    new_chart = self.func_map[name_func]()
            # Example Mapping Output. Alternatively, just: `return [new_chart]`
            return map_outputs(outputs, [(self.id_chart, 'figure', new_chart)])

return_layout⚓︎

def return_layout(
    self
) -> dict

Return Dash application layout.

Returns:

Type Description
dict Dash HTML object
View Source
    def return_layout(self) -> dict:
        """Return Dash application layout.

        Returns:
            dict: Dash HTML object

        """
        self.verify_types_for_layout()

        return html.Div(
            [  # noqa: ECE001
                html.Div(
                    [
                        dropdown_group(
                            'Plot Type:', self._il[self.id_func],
                            self.func_opts, value=self.func_opts[0]['label'],
                        ),
                        dropdown_group(
                            'Template:', self._il[self.id_template],
                            self.t_opts, value=self.t_opts[0]['label'],
                        ),
                    ] + [
                        dropdown_group(
                            f'{dim}:', self._il[dim], self.col_opts,
                            value=self.default_dim_name.get(dim, None),
                        )
                        for dim in self.dims
                    ] + [
                        dropdown_group(f'{dim}:', self._il[dim], [opts_dd(item, item) for item in items])
                        for dim, items in self.dims_dict.items()
                    ], style={'width': '25%', 'float': 'left'},
                ),
                min_graph(id=self._il[self.id_chart], style={'width': '75%', 'display': 'inline-block'}),
            ], style={'padding': '15px'},
        )

run⚓︎

def run(
    self,
    **dash_kwargs: dict
) -> None

Launch the Dash server instance.

Parameters:

Name Description
**dash_kwargs keyword arguments for Dash.run_server()
View Source
    def run(self, **dash_kwargs: dict) -> None:
        """Launch the Dash server instance.

        Args:
            **dash_kwargs: keyword arguments for `Dash.run_server()`

        """
        self.app.run_server(**dash_kwargs)  # pragma: no cover

verify_app_initialization⚓︎

def verify_app_initialization(
    self
) -> None

Check that the app was properly initialized.

Raises:

Type Description
RuntimeError if child class has not called self.register_uniq_ids
View Source
    def verify_app_initialization(self) -> None:
        """Check that the app was properly initialized.

        Raises:
            RuntimeError: if child class has not called `self.register_uniq_ids`

        """
        if not self._il.keys():  # pragma: no cover
            raise RuntimeError('Child class must first call `self.register_uniq_ids(__)` before self.run()')

verify_types_for_callbacks⚓︎

def verify_types_for_callbacks(
    self
)

Verify data types of data members necessary for the callbacks of this tab.

Raises:

Type Description
RuntimeError if any relevant data members are of the wrong type
View Source
    def verify_types_for_callbacks(self):
        """Verify data types of data members necessary for the callbacks of this tab.

        Raises:
            RuntimeError: if any relevant data members are of the wrong type

        """
        errors = []
        if not isinstance(self.takes_args, bool):
            errors.append(f'Expected self.takes_args="{self.takes_args}" to be bool')
        if not (isinstance(self.data, pd.DataFrame) or self.data is None):
            errors.append(f'Expected self.data="{self.data}" to be pd.DataFrame or None')
        if not isinstance(self.func_map, OrderedDict):
            errors.append(f'Expected self.func_map="{self.func_map}" to be OrderedDict')
        if errors:
            formatted_errors = '\n' + '\n'.join(errors)
            raise RuntimeError(f'Found errors in data members:{formatted_errors}')

verify_types_for_layout⚓︎

def verify_types_for_layout(
    self
)

Verify data types of data members necessary for the layout of this tab.

Raises:

Type Description
RuntimeError if any relevant data members are of the wrong type
View Source
    def verify_types_for_layout(self):
        """Verify data types of data members necessary for the layout of this tab.

        Raises:
            RuntimeError: if any relevant data members are of the wrong type

        """
        errors = []
        if not isinstance(self.name, str):
            errors.append(f'Expected self.name="{self.name}" to be str')
        if not isinstance(self.dims, tuple):
            errors.append(f'Expected self.dims="{self.dims}" to be tuple')
        if not isinstance(self.dims_dict, OrderedDict):
            errors.append(f'Expected self.dims_dict="{self.dims_dict}" to be OrderedDict')
        if errors:
            formatted_errors = '\n' + '\n'.join(errors)
            raise RuntimeError(f'Found errors in data members:{formatted_errors}')

TabColor⚓︎

class TabColor(
    app: Union[dash.dash.Dash, NoneType] = None
)
View Source
class TabColor(TabBase):
    """TabColor properties."""

    name = 'Color Swatches'
    takes_args = False
    func_map = OrderedDict([
        ('colors.qualitative', px.colors.qualitative.swatches),
        ('colors.sequential', px.colors.sequential.swatches),
        ('colors.diverging', px.colors.diverging.swatches),
        ('colors.cyclical', px.colors.cyclical.swatches),
        ('colors.colorbrewer', px.colors.colorbrewer.swatches),
        ('colors.cmocean', px.colors.cmocean.swatches),
        ('colors.carto', px.colors.carto.swatches),
    ])
    default_dim_name = {
        'x': 'sepal_width',
        'y': 'sepal_length',
    }

Ancestors (in MRO)⚓︎

  • dash_charts.app_px.TabBase
  • dash_charts.utils_app.AppBase

Class variables⚓︎

data
default_dim_name
dims
dims_dict
external_stylesheets
func_map
id_chart
id_func
id_template
init_app_kwargs
modules
name
nsi
takes_args
templates
validation_layout

Methods⚓︎

callback⚓︎

def callback(
    self,
    outputs,
    inputs,
    states,
    pic: bool = False,
    **kwargs: dict
)

Return app callback decorator based on provided components.

Parameters:

Name Description
outputs list of tuples with app_id and property name
inputs list of tuples with app_id and property name
states list of tuples with app_id and property name
pic If True, prevent call on page load (prevent_initial_call). Default is False
**kwargs any additional keyword arguments for self.app.callback

Returns:

Type Description
dict result of self.app.callback()
View Source
    def callback(self, outputs, inputs, states, pic: bool = False, **kwargs: dict):
        """Return app callback decorator based on provided components.

        Args:
            outputs: list of tuples with app_id and property name
            inputs: list of tuples with app_id and property name
            states: list of tuples with app_id and property name
            pic: If True, prevent call on page load (`prevent_initial_call`). Default is False
            **kwargs: any additional keyword arguments for `self.app.callback`

        Returns:
            dict: result of `self.app.callback()`

        """
        return self.app.callback(
            *format_app_callback(self._il, outputs, inputs, states),
            prevent_initial_call=pic,
            **kwargs,
        )

create⚓︎

def create(
    self,
    assign_layout: bool = True
) -> None

Create the ids, app charts, layout, callbacks, and optional modules.

Parameters:

Name Description
assign_layout if True, will assign self.app.layout. If False, must call self.return_layout separately.
Default is True

Raises:

Type Description
NotImplementedError if child class has not set the self.name data member
View Source
    def create(self, assign_layout: bool = True) -> None:  # noqa: CCR001
        """Create the ids, app charts, layout, callbacks, and optional modules.

        Args:
            assign_layout: if True, will assign `self.app.layout`. If False, must call `self.return_layout` separately.
                Default is True

        Raises:
            NotImplementedError: if child class has not set the `self.name` data member

        """
        if self.name is None:  # pragma: no cover
            raise NotImplementedError('Child class must set `self.name` to a unique string for this app')

        # Initialize app and each module
        self.initialization()
        for mod in self.modules:
            self.register_uniq_ids(mod.all_ids)
        self.override_module_defaults()  # Call optional override method

        # Create charts for app and each module
        self.create_elements()
        for mod in self.modules:
            mod.create_elements(self._il)

        # Create app layout. User must call the return_layout method from each module within own return_layout method
        if assign_layout:
            self.app.layout = self.return_layout()
        if assign_layout and self.validation_layout:
            self.app.validation_layout = [deepcopy(self.app.layout)] + self.validation_layout
            pprint('\n\nValidationLayout?')
            pprint(self.app.validation_layout)

        # Create callbacks for app and each module
        self.create_callbacks()
        for mod in self.modules:
            mod.create_callbacks(self)

        self.verify_app_initialization()

create_callbacks⚓︎

def create_callbacks(
    self
) -> None

Register callbacks necessary for this tab.

View Source
    def create_callbacks(self) -> None:
        """Register callbacks necessary for this tab."""
        self.verify_types_for_callbacks()

        self.register_update_chart()

create_elements⚓︎

def create_elements(
    self
) -> None

Initialize the charts, tables, and other Dash elements.

View Source
    def create_elements(self) -> None:
        """Initialize the charts, tables, and other Dash elements."""
        ...

generate_data⚓︎

def generate_data(
    self
) -> None

Recommended method for generating data stored in memory. Called in initialization.

View Source
    def generate_data(self) -> None:
        """Recommended method for generating data stored in memory. Called in initialization."""
        ...

get_server⚓︎

def get_server(
    self
)

Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

Returns:

Type Description
dict the Flask server component of the Dash app
View Source
    def get_server(self):
        """Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

        Returns:
            dict: the Flask `server` component of the Dash app

        """
        return self.app.server

initialization⚓︎

def initialization(
    self
) -> None

Initialize ids with self.register_uniq_ids([...]) and other one-time actions.

View Source
    def initialization(self) -> None:
        """Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
        super().initialization()

        # Register the the unique element IDs
        self.input_ids = [self.id_func, self.id_template] + [*self.dims] + [*self.dims_dict.keys()]
        self.register_uniq_ids([self.id_chart] + self.input_ids)

        # Configure the options for the various dropdowns
        self.col_opts = [] if self.data is None else tuple(opts_dd(_c, _c) for _c in self.data.columns)
        self.func_opts = tuple(opts_dd(lbl, lbl) for lbl in self.func_map.keys())
        self.t_opts = tuple(opts_dd(template, template) for template in self.templates)

override_module_defaults⚓︎

def override_module_defaults(
    self
) -> None

Override default values from modules.

View Source
    def override_module_defaults(self) -> None:
        """Override default values from modules."""
        ...

register_uniq_ids⚓︎

def register_uniq_ids(
    self,
    app_ids: List[str]
) -> None

Register the app_ids to the corresponding global_id in the self._il lookup dictionary.

The app_ids must be unique within this App so that a layout can be created. This method registers self._il which are a list of globally unique ids (incorporating this App’s unique self.name) allowing for the child class of this base App to be resused multiple times within a tabbed or multi-page application without id-collision

Parameters:

Name Description
app_ids list of strings that are unique within this App
View Source
    def register_uniq_ids(self, app_ids: List[str]) -> None:
        """Register the `app_ids` to the corresponding global_id in the `self._il` lookup dictionary.

        The app_ids must be unique within this App so that a layout can be created. This method registers `self._il`
          which are a list of globally unique ids (incorporating this App's unique `self.name`) allowing for the child
          class of this base App to be resused multiple times within a tabbed or multi-page application without
          id-collision

        Args:
            app_ids: list of strings that are unique within this App

        """
        self._il = deepcopy(self._il)
        for app_id in app_ids:
            self._il[app_id] = f'{self.name}-{app_id}'.replace(' ', '-')

register_update_chart⚓︎

def register_update_chart(
    self
)

Register the update_chart callback.

View Source
    def register_update_chart(self):   # noqa: CCR001
        """Register the update_chart callback."""
        outputs = [(self.id_chart, 'figure')]
        inputs = [(_id, 'value') for _id in self.input_ids]
        states = ()

        @self.callback(outputs, inputs, states)
        def update_chart(*raw_args):
            a_in, _a_states = map_args(raw_args, inputs, states)
            name_func = a_in[self.id_func]['value']

            properties = [trigger['prop_id'] for trigger in dash.callback_context.triggered]
            new_chart = {}
            # If event is not a tab change, return the updated chart
            if 'tabs-select.value' not in properties:  # FIXME: replace tabs-select with actual keyname (?)
                if self.takes_args:
                    # Parse the arguments to generate a new plot
                    kwargs = {key: a_in[key]['value'] for key in self.input_ids[1:]}
                    new_chart = self.func_map[name_func](self.data, height=650, **kwargs)
                else:
                    new_chart = self.func_map[name_func]()
            # Example Mapping Output. Alternatively, just: `return [new_chart]`
            return map_outputs(outputs, [(self.id_chart, 'figure', new_chart)])

return_layout⚓︎

def return_layout(
    self
) -> dict

Return Dash application layout.

Returns:

Type Description
dict Dash HTML object
View Source
    def return_layout(self) -> dict:
        """Return Dash application layout.

        Returns:
            dict: Dash HTML object

        """
        self.verify_types_for_layout()

        return html.Div(
            [  # noqa: ECE001
                html.Div(
                    [
                        dropdown_group(
                            'Plot Type:', self._il[self.id_func],
                            self.func_opts, value=self.func_opts[0]['label'],
                        ),
                        dropdown_group(
                            'Template:', self._il[self.id_template],
                            self.t_opts, value=self.t_opts[0]['label'],
                        ),
                    ] + [
                        dropdown_group(
                            f'{dim}:', self._il[dim], self.col_opts,
                            value=self.default_dim_name.get(dim, None),
                        )
                        for dim in self.dims
                    ] + [
                        dropdown_group(f'{dim}:', self._il[dim], [opts_dd(item, item) for item in items])
                        for dim, items in self.dims_dict.items()
                    ], style={'width': '25%', 'float': 'left'},
                ),
                min_graph(id=self._il[self.id_chart], style={'width': '75%', 'display': 'inline-block'}),
            ], style={'padding': '15px'},
        )

run⚓︎

def run(
    self,
    **dash_kwargs: dict
) -> None

Launch the Dash server instance.

Parameters:

Name Description
**dash_kwargs keyword arguments for Dash.run_server()
View Source
    def run(self, **dash_kwargs: dict) -> None:
        """Launch the Dash server instance.

        Args:
            **dash_kwargs: keyword arguments for `Dash.run_server()`

        """
        self.app.run_server(**dash_kwargs)  # pragma: no cover

verify_app_initialization⚓︎

def verify_app_initialization(
    self
) -> None

Check that the app was properly initialized.

Raises:

Type Description
RuntimeError if child class has not called self.register_uniq_ids
View Source
    def verify_app_initialization(self) -> None:
        """Check that the app was properly initialized.

        Raises:
            RuntimeError: if child class has not called `self.register_uniq_ids`

        """
        if not self._il.keys():  # pragma: no cover
            raise RuntimeError('Child class must first call `self.register_uniq_ids(__)` before self.run()')

verify_types_for_callbacks⚓︎

def verify_types_for_callbacks(
    self
)

Verify data types of data members necessary for the callbacks of this tab.

Raises:

Type Description
RuntimeError if any relevant data members are of the wrong type
View Source
    def verify_types_for_callbacks(self):
        """Verify data types of data members necessary for the callbacks of this tab.

        Raises:
            RuntimeError: if any relevant data members are of the wrong type

        """
        errors = []
        if not isinstance(self.takes_args, bool):
            errors.append(f'Expected self.takes_args="{self.takes_args}" to be bool')
        if not (isinstance(self.data, pd.DataFrame) or self.data is None):
            errors.append(f'Expected self.data="{self.data}" to be pd.DataFrame or None')
        if not isinstance(self.func_map, OrderedDict):
            errors.append(f'Expected self.func_map="{self.func_map}" to be OrderedDict')
        if errors:
            formatted_errors = '\n' + '\n'.join(errors)
            raise RuntimeError(f'Found errors in data members:{formatted_errors}')

verify_types_for_layout⚓︎

def verify_types_for_layout(
    self
)

Verify data types of data members necessary for the layout of this tab.

Raises:

Type Description
RuntimeError if any relevant data members are of the wrong type
View Source
    def verify_types_for_layout(self):
        """Verify data types of data members necessary for the layout of this tab.

        Raises:
            RuntimeError: if any relevant data members are of the wrong type

        """
        errors = []
        if not isinstance(self.name, str):
            errors.append(f'Expected self.name="{self.name}" to be str')
        if not isinstance(self.dims, tuple):
            errors.append(f'Expected self.dims="{self.dims}" to be tuple')
        if not isinstance(self.dims_dict, OrderedDict):
            errors.append(f'Expected self.dims_dict="{self.dims_dict}" to be OrderedDict')
        if errors:
            formatted_errors = '\n' + '\n'.join(errors)
            raise RuntimeError(f'Found errors in data members:{formatted_errors}')

TabGapminder⚓︎

class TabGapminder(
    app: Union[dash.dash.Dash, NoneType] = None
)
View Source
class TabGapminder(TabBase):
    """TabGapminder properties."""

    name = 'Gapminder Data'
    data = px.data.gapminder()
    func_map = OrderedDict([
        ('area', px.area),
        ('line', px.line),
    ])
    dims = ('x', 'y', 'color', 'line_group', 'facet_row', 'facet_col')
    default_dim_name = {
        'x': 'year',
        'y': 'pop',
        'color': 'continent',
        'line_group': 'country',
    }

Ancestors (in MRO)⚓︎

  • dash_charts.app_px.TabBase
  • dash_charts.utils_app.AppBase

Class variables⚓︎

data
default_dim_name
dims
dims_dict
external_stylesheets
func_map
id_chart
id_func
id_template
init_app_kwargs
modules
name
nsi
takes_args
templates
validation_layout

Methods⚓︎

callback⚓︎

def callback(
    self,
    outputs,
    inputs,
    states,
    pic: bool = False,
    **kwargs: dict
)

Return app callback decorator based on provided components.

Parameters:

Name Description
outputs list of tuples with app_id and property name
inputs list of tuples with app_id and property name
states list of tuples with app_id and property name
pic If True, prevent call on page load (prevent_initial_call). Default is False
**kwargs any additional keyword arguments for self.app.callback

Returns:

Type Description
dict result of self.app.callback()
View Source
    def callback(self, outputs, inputs, states, pic: bool = False, **kwargs: dict):
        """Return app callback decorator based on provided components.

        Args:
            outputs: list of tuples with app_id and property name
            inputs: list of tuples with app_id and property name
            states: list of tuples with app_id and property name
            pic: If True, prevent call on page load (`prevent_initial_call`). Default is False
            **kwargs: any additional keyword arguments for `self.app.callback`

        Returns:
            dict: result of `self.app.callback()`

        """
        return self.app.callback(
            *format_app_callback(self._il, outputs, inputs, states),
            prevent_initial_call=pic,
            **kwargs,
        )

create⚓︎

def create(
    self,
    assign_layout: bool = True
) -> None

Create the ids, app charts, layout, callbacks, and optional modules.

Parameters:

Name Description
assign_layout if True, will assign self.app.layout. If False, must call self.return_layout separately.
Default is True

Raises:

Type Description
NotImplementedError if child class has not set the self.name data member
View Source
    def create(self, assign_layout: bool = True) -> None:  # noqa: CCR001
        """Create the ids, app charts, layout, callbacks, and optional modules.

        Args:
            assign_layout: if True, will assign `self.app.layout`. If False, must call `self.return_layout` separately.
                Default is True

        Raises:
            NotImplementedError: if child class has not set the `self.name` data member

        """
        if self.name is None:  # pragma: no cover
            raise NotImplementedError('Child class must set `self.name` to a unique string for this app')

        # Initialize app and each module
        self.initialization()
        for mod in self.modules:
            self.register_uniq_ids(mod.all_ids)
        self.override_module_defaults()  # Call optional override method

        # Create charts for app and each module
        self.create_elements()
        for mod in self.modules:
            mod.create_elements(self._il)

        # Create app layout. User must call the return_layout method from each module within own return_layout method
        if assign_layout:
            self.app.layout = self.return_layout()
        if assign_layout and self.validation_layout:
            self.app.validation_layout = [deepcopy(self.app.layout)] + self.validation_layout
            pprint('\n\nValidationLayout?')
            pprint(self.app.validation_layout)

        # Create callbacks for app and each module
        self.create_callbacks()
        for mod in self.modules:
            mod.create_callbacks(self)

        self.verify_app_initialization()

create_callbacks⚓︎

def create_callbacks(
    self
) -> None

Register callbacks necessary for this tab.

View Source
    def create_callbacks(self) -> None:
        """Register callbacks necessary for this tab."""
        self.verify_types_for_callbacks()

        self.register_update_chart()

create_elements⚓︎

def create_elements(
    self
) -> None

Initialize the charts, tables, and other Dash elements.

View Source
    def create_elements(self) -> None:
        """Initialize the charts, tables, and other Dash elements."""
        ...

generate_data⚓︎

def generate_data(
    self
) -> None

Recommended method for generating data stored in memory. Called in initialization.

View Source
    def generate_data(self) -> None:
        """Recommended method for generating data stored in memory. Called in initialization."""
        ...

get_server⚓︎

def get_server(
    self
)

Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

Returns:

Type Description
dict the Flask server component of the Dash app
View Source
    def get_server(self):
        """Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

        Returns:
            dict: the Flask `server` component of the Dash app

        """
        return self.app.server

initialization⚓︎

def initialization(
    self
) -> None

Initialize ids with self.register_uniq_ids([...]) and other one-time actions.

View Source
    def initialization(self) -> None:
        """Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
        super().initialization()

        # Register the the unique element IDs
        self.input_ids = [self.id_func, self.id_template] + [*self.dims] + [*self.dims_dict.keys()]
        self.register_uniq_ids([self.id_chart] + self.input_ids)

        # Configure the options for the various dropdowns
        self.col_opts = [] if self.data is None else tuple(opts_dd(_c, _c) for _c in self.data.columns)
        self.func_opts = tuple(opts_dd(lbl, lbl) for lbl in self.func_map.keys())
        self.t_opts = tuple(opts_dd(template, template) for template in self.templates)

override_module_defaults⚓︎

def override_module_defaults(
    self
) -> None

Override default values from modules.

View Source
    def override_module_defaults(self) -> None:
        """Override default values from modules."""
        ...

register_uniq_ids⚓︎

def register_uniq_ids(
    self,
    app_ids: List[str]
) -> None

Register the app_ids to the corresponding global_id in the self._il lookup dictionary.

The app_ids must be unique within this App so that a layout can be created. This method registers self._il which are a list of globally unique ids (incorporating this App’s unique self.name) allowing for the child class of this base App to be resused multiple times within a tabbed or multi-page application without id-collision

Parameters:

Name Description
app_ids list of strings that are unique within this App
View Source
    def register_uniq_ids(self, app_ids: List[str]) -> None:
        """Register the `app_ids` to the corresponding global_id in the `self._il` lookup dictionary.

        The app_ids must be unique within this App so that a layout can be created. This method registers `self._il`
          which are a list of globally unique ids (incorporating this App's unique `self.name`) allowing for the child
          class of this base App to be resused multiple times within a tabbed or multi-page application without
          id-collision

        Args:
            app_ids: list of strings that are unique within this App

        """
        self._il = deepcopy(self._il)
        for app_id in app_ids:
            self._il[app_id] = f'{self.name}-{app_id}'.replace(' ', '-')

register_update_chart⚓︎

def register_update_chart(
    self
)

Register the update_chart callback.

View Source
    def register_update_chart(self):   # noqa: CCR001
        """Register the update_chart callback."""
        outputs = [(self.id_chart, 'figure')]
        inputs = [(_id, 'value') for _id in self.input_ids]
        states = ()

        @self.callback(outputs, inputs, states)
        def update_chart(*raw_args):
            a_in, _a_states = map_args(raw_args, inputs, states)
            name_func = a_in[self.id_func]['value']

            properties = [trigger['prop_id'] for trigger in dash.callback_context.triggered]
            new_chart = {}
            # If event is not a tab change, return the updated chart
            if 'tabs-select.value' not in properties:  # FIXME: replace tabs-select with actual keyname (?)
                if self.takes_args:
                    # Parse the arguments to generate a new plot
                    kwargs = {key: a_in[key]['value'] for key in self.input_ids[1:]}
                    new_chart = self.func_map[name_func](self.data, height=650, **kwargs)
                else:
                    new_chart = self.func_map[name_func]()
            # Example Mapping Output. Alternatively, just: `return [new_chart]`
            return map_outputs(outputs, [(self.id_chart, 'figure', new_chart)])

return_layout⚓︎

def return_layout(
    self
) -> dict

Return Dash application layout.

Returns:

Type Description
dict Dash HTML object
View Source
    def return_layout(self) -> dict:
        """Return Dash application layout.

        Returns:
            dict: Dash HTML object

        """
        self.verify_types_for_layout()

        return html.Div(
            [  # noqa: ECE001
                html.Div(
                    [
                        dropdown_group(
                            'Plot Type:', self._il[self.id_func],
                            self.func_opts, value=self.func_opts[0]['label'],
                        ),
                        dropdown_group(
                            'Template:', self._il[self.id_template],
                            self.t_opts, value=self.t_opts[0]['label'],
                        ),
                    ] + [
                        dropdown_group(
                            f'{dim}:', self._il[dim], self.col_opts,
                            value=self.default_dim_name.get(dim, None),
                        )
                        for dim in self.dims
                    ] + [
                        dropdown_group(f'{dim}:', self._il[dim], [opts_dd(item, item) for item in items])
                        for dim, items in self.dims_dict.items()
                    ], style={'width': '25%', 'float': 'left'},
                ),
                min_graph(id=self._il[self.id_chart], style={'width': '75%', 'display': 'inline-block'}),
            ], style={'padding': '15px'},
        )

run⚓︎

def run(
    self,
    **dash_kwargs: dict
) -> None

Launch the Dash server instance.

Parameters:

Name Description
**dash_kwargs keyword arguments for Dash.run_server()
View Source
    def run(self, **dash_kwargs: dict) -> None:
        """Launch the Dash server instance.

        Args:
            **dash_kwargs: keyword arguments for `Dash.run_server()`

        """
        self.app.run_server(**dash_kwargs)  # pragma: no cover

verify_app_initialization⚓︎

def verify_app_initialization(
    self
) -> None

Check that the app was properly initialized.

Raises:

Type Description
RuntimeError if child class has not called self.register_uniq_ids
View Source
    def verify_app_initialization(self) -> None:
        """Check that the app was properly initialized.

        Raises:
            RuntimeError: if child class has not called `self.register_uniq_ids`

        """
        if not self._il.keys():  # pragma: no cover
            raise RuntimeError('Child class must first call `self.register_uniq_ids(__)` before self.run()')

verify_types_for_callbacks⚓︎

def verify_types_for_callbacks(
    self
)

Verify data types of data members necessary for the callbacks of this tab.

Raises:

Type Description
RuntimeError if any relevant data members are of the wrong type
View Source
    def verify_types_for_callbacks(self):
        """Verify data types of data members necessary for the callbacks of this tab.

        Raises:
            RuntimeError: if any relevant data members are of the wrong type

        """
        errors = []
        if not isinstance(self.takes_args, bool):
            errors.append(f'Expected self.takes_args="{self.takes_args}" to be bool')
        if not (isinstance(self.data, pd.DataFrame) or self.data is None):
            errors.append(f'Expected self.data="{self.data}" to be pd.DataFrame or None')
        if not isinstance(self.func_map, OrderedDict):
            errors.append(f'Expected self.func_map="{self.func_map}" to be OrderedDict')
        if errors:
            formatted_errors = '\n' + '\n'.join(errors)
            raise RuntimeError(f'Found errors in data members:{formatted_errors}')

verify_types_for_layout⚓︎

def verify_types_for_layout(
    self
)

Verify data types of data members necessary for the layout of this tab.

Raises:

Type Description
RuntimeError if any relevant data members are of the wrong type
View Source
    def verify_types_for_layout(self):
        """Verify data types of data members necessary for the layout of this tab.

        Raises:
            RuntimeError: if any relevant data members are of the wrong type

        """
        errors = []
        if not isinstance(self.name, str):
            errors.append(f'Expected self.name="{self.name}" to be str')
        if not isinstance(self.dims, tuple):
            errors.append(f'Expected self.dims="{self.dims}" to be tuple')
        if not isinstance(self.dims_dict, OrderedDict):
            errors.append(f'Expected self.dims_dict="{self.dims_dict}" to be OrderedDict')
        if errors:
            formatted_errors = '\n' + '\n'.join(errors)
            raise RuntimeError(f'Found errors in data members:{formatted_errors}')

TabIris⚓︎

class TabIris(
    app: Union[dash.dash.Dash, NoneType] = None
)
View Source
class TabIris(TabBase):
    """TabIris properties."""

    name = 'Iris Data'
    data = px.data.iris()
    func_map = OrderedDict([
        ('histogram', px.histogram),
        ('bar', px.bar),
        ('strip', px.strip),
        ('box', px.box),
        ('violin', px.violin),
    ])
    dims = ('x', 'y', 'color', 'facet_row', 'facet_col')
    default_dim_name = {
        'x': 'sepal_width',
        'color': 'species',
    }

Ancestors (in MRO)⚓︎

  • dash_charts.app_px.TabBase
  • dash_charts.utils_app.AppBase

Class variables⚓︎

data
default_dim_name
dims
dims_dict
external_stylesheets
func_map
id_chart
id_func
id_template
init_app_kwargs
modules
name
nsi
takes_args
templates
validation_layout

Methods⚓︎

callback⚓︎

def callback(
    self,
    outputs,
    inputs,
    states,
    pic: bool = False,
    **kwargs: dict
)

Return app callback decorator based on provided components.

Parameters:

Name Description
outputs list of tuples with app_id and property name
inputs list of tuples with app_id and property name
states list of tuples with app_id and property name
pic If True, prevent call on page load (prevent_initial_call). Default is False
**kwargs any additional keyword arguments for self.app.callback

Returns:

Type Description
dict result of self.app.callback()
View Source
    def callback(self, outputs, inputs, states, pic: bool = False, **kwargs: dict):
        """Return app callback decorator based on provided components.

        Args:
            outputs: list of tuples with app_id and property name
            inputs: list of tuples with app_id and property name
            states: list of tuples with app_id and property name
            pic: If True, prevent call on page load (`prevent_initial_call`). Default is False
            **kwargs: any additional keyword arguments for `self.app.callback`

        Returns:
            dict: result of `self.app.callback()`

        """
        return self.app.callback(
            *format_app_callback(self._il, outputs, inputs, states),
            prevent_initial_call=pic,
            **kwargs,
        )

create⚓︎

def create(
    self,
    assign_layout: bool = True
) -> None

Create the ids, app charts, layout, callbacks, and optional modules.

Parameters:

Name Description
assign_layout if True, will assign self.app.layout. If False, must call self.return_layout separately.
Default is True

Raises:

Type Description
NotImplementedError if child class has not set the self.name data member
View Source
    def create(self, assign_layout: bool = True) -> None:  # noqa: CCR001
        """Create the ids, app charts, layout, callbacks, and optional modules.

        Args:
            assign_layout: if True, will assign `self.app.layout`. If False, must call `self.return_layout` separately.
                Default is True

        Raises:
            NotImplementedError: if child class has not set the `self.name` data member

        """
        if self.name is None:  # pragma: no cover
            raise NotImplementedError('Child class must set `self.name` to a unique string for this app')

        # Initialize app and each module
        self.initialization()
        for mod in self.modules:
            self.register_uniq_ids(mod.all_ids)
        self.override_module_defaults()  # Call optional override method

        # Create charts for app and each module
        self.create_elements()
        for mod in self.modules:
            mod.create_elements(self._il)

        # Create app layout. User must call the return_layout method from each module within own return_layout method
        if assign_layout:
            self.app.layout = self.return_layout()
        if assign_layout and self.validation_layout:
            self.app.validation_layout = [deepcopy(self.app.layout)] + self.validation_layout
            pprint('\n\nValidationLayout?')
            pprint(self.app.validation_layout)

        # Create callbacks for app and each module
        self.create_callbacks()
        for mod in self.modules:
            mod.create_callbacks(self)

        self.verify_app_initialization()

create_callbacks⚓︎

def create_callbacks(
    self
) -> None

Register callbacks necessary for this tab.

View Source
    def create_callbacks(self) -> None:
        """Register callbacks necessary for this tab."""
        self.verify_types_for_callbacks()

        self.register_update_chart()

create_elements⚓︎

def create_elements(
    self
) -> None

Initialize the charts, tables, and other Dash elements.

View Source
    def create_elements(self) -> None:
        """Initialize the charts, tables, and other Dash elements."""
        ...

generate_data⚓︎

def generate_data(
    self
) -> None

Recommended method for generating data stored in memory. Called in initialization.

View Source
    def generate_data(self) -> None:
        """Recommended method for generating data stored in memory. Called in initialization."""
        ...

get_server⚓︎

def get_server(
    self
)

Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

Returns:

Type Description
dict the Flask server component of the Dash app
View Source
    def get_server(self):
        """Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

        Returns:
            dict: the Flask `server` component of the Dash app

        """
        return self.app.server

initialization⚓︎

def initialization(
    self
) -> None

Initialize ids with self.register_uniq_ids([...]) and other one-time actions.

View Source
    def initialization(self) -> None:
        """Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
        super().initialization()

        # Register the the unique element IDs
        self.input_ids = [self.id_func, self.id_template] + [*self.dims] + [*self.dims_dict.keys()]
        self.register_uniq_ids([self.id_chart] + self.input_ids)

        # Configure the options for the various dropdowns
        self.col_opts = [] if self.data is None else tuple(opts_dd(_c, _c) for _c in self.data.columns)
        self.func_opts = tuple(opts_dd(lbl, lbl) for lbl in self.func_map.keys())
        self.t_opts = tuple(opts_dd(template, template) for template in self.templates)

override_module_defaults⚓︎

def override_module_defaults(
    self
) -> None

Override default values from modules.

View Source
    def override_module_defaults(self) -> None:
        """Override default values from modules."""
        ...

register_uniq_ids⚓︎

def register_uniq_ids(
    self,
    app_ids: List[str]
) -> None

Register the app_ids to the corresponding global_id in the self._il lookup dictionary.

The app_ids must be unique within this App so that a layout can be created. This method registers self._il which are a list of globally unique ids (incorporating this App’s unique self.name) allowing for the child class of this base App to be resused multiple times within a tabbed or multi-page application without id-collision

Parameters:

Name Description
app_ids list of strings that are unique within this App
View Source
    def register_uniq_ids(self, app_ids: List[str]) -> None:
        """Register the `app_ids` to the corresponding global_id in the `self._il` lookup dictionary.

        The app_ids must be unique within this App so that a layout can be created. This method registers `self._il`
          which are a list of globally unique ids (incorporating this App's unique `self.name`) allowing for the child
          class of this base App to be resused multiple times within a tabbed or multi-page application without
          id-collision

        Args:
            app_ids: list of strings that are unique within this App

        """
        self._il = deepcopy(self._il)
        for app_id in app_ids:
            self._il[app_id] = f'{self.name}-{app_id}'.replace(' ', '-')

register_update_chart⚓︎

def register_update_chart(
    self
)

Register the update_chart callback.

View Source
    def register_update_chart(self):   # noqa: CCR001
        """Register the update_chart callback."""
        outputs = [(self.id_chart, 'figure')]
        inputs = [(_id, 'value') for _id in self.input_ids]
        states = ()

        @self.callback(outputs, inputs, states)
        def update_chart(*raw_args):
            a_in, _a_states = map_args(raw_args, inputs, states)
            name_func = a_in[self.id_func]['value']

            properties = [trigger['prop_id'] for trigger in dash.callback_context.triggered]
            new_chart = {}
            # If event is not a tab change, return the updated chart
            if 'tabs-select.value' not in properties:  # FIXME: replace tabs-select with actual keyname (?)
                if self.takes_args:
                    # Parse the arguments to generate a new plot
                    kwargs = {key: a_in[key]['value'] for key in self.input_ids[1:]}
                    new_chart = self.func_map[name_func](self.data, height=650, **kwargs)
                else:
                    new_chart = self.func_map[name_func]()
            # Example Mapping Output. Alternatively, just: `return [new_chart]`
            return map_outputs(outputs, [(self.id_chart, 'figure', new_chart)])

return_layout⚓︎

def return_layout(
    self
) -> dict

Return Dash application layout.

Returns:

Type Description
dict Dash HTML object
View Source
    def return_layout(self) -> dict:
        """Return Dash application layout.

        Returns:
            dict: Dash HTML object

        """
        self.verify_types_for_layout()

        return html.Div(
            [  # noqa: ECE001
                html.Div(
                    [
                        dropdown_group(
                            'Plot Type:', self._il[self.id_func],
                            self.func_opts, value=self.func_opts[0]['label'],
                        ),
                        dropdown_group(
                            'Template:', self._il[self.id_template],
                            self.t_opts, value=self.t_opts[0]['label'],
                        ),
                    ] + [
                        dropdown_group(
                            f'{dim}:', self._il[dim], self.col_opts,
                            value=self.default_dim_name.get(dim, None),
                        )
                        for dim in self.dims
                    ] + [
                        dropdown_group(f'{dim}:', self._il[dim], [opts_dd(item, item) for item in items])
                        for dim, items in self.dims_dict.items()
                    ], style={'width': '25%', 'float': 'left'},
                ),
                min_graph(id=self._il[self.id_chart], style={'width': '75%', 'display': 'inline-block'}),
            ], style={'padding': '15px'},
        )

run⚓︎

def run(
    self,
    **dash_kwargs: dict
) -> None

Launch the Dash server instance.

Parameters:

Name Description
**dash_kwargs keyword arguments for Dash.run_server()
View Source
    def run(self, **dash_kwargs: dict) -> None:
        """Launch the Dash server instance.

        Args:
            **dash_kwargs: keyword arguments for `Dash.run_server()`

        """
        self.app.run_server(**dash_kwargs)  # pragma: no cover

verify_app_initialization⚓︎

def verify_app_initialization(
    self
) -> None

Check that the app was properly initialized.

Raises:

Type Description
RuntimeError if child class has not called self.register_uniq_ids
View Source
    def verify_app_initialization(self) -> None:
        """Check that the app was properly initialized.

        Raises:
            RuntimeError: if child class has not called `self.register_uniq_ids`

        """
        if not self._il.keys():  # pragma: no cover
            raise RuntimeError('Child class must first call `self.register_uniq_ids(__)` before self.run()')

verify_types_for_callbacks⚓︎

def verify_types_for_callbacks(
    self
)

Verify data types of data members necessary for the callbacks of this tab.

Raises:

Type Description
RuntimeError if any relevant data members are of the wrong type
View Source
    def verify_types_for_callbacks(self):
        """Verify data types of data members necessary for the callbacks of this tab.

        Raises:
            RuntimeError: if any relevant data members are of the wrong type

        """
        errors = []
        if not isinstance(self.takes_args, bool):
            errors.append(f'Expected self.takes_args="{self.takes_args}" to be bool')
        if not (isinstance(self.data, pd.DataFrame) or self.data is None):
            errors.append(f'Expected self.data="{self.data}" to be pd.DataFrame or None')
        if not isinstance(self.func_map, OrderedDict):
            errors.append(f'Expected self.func_map="{self.func_map}" to be OrderedDict')
        if errors:
            formatted_errors = '\n' + '\n'.join(errors)
            raise RuntimeError(f'Found errors in data members:{formatted_errors}')

verify_types_for_layout⚓︎

def verify_types_for_layout(
    self
)

Verify data types of data members necessary for the layout of this tab.

Raises:

Type Description
RuntimeError if any relevant data members are of the wrong type
View Source
    def verify_types_for_layout(self):
        """Verify data types of data members necessary for the layout of this tab.

        Raises:
            RuntimeError: if any relevant data members are of the wrong type

        """
        errors = []
        if not isinstance(self.name, str):
            errors.append(f'Expected self.name="{self.name}" to be str')
        if not isinstance(self.dims, tuple):
            errors.append(f'Expected self.dims="{self.dims}" to be tuple')
        if not isinstance(self.dims_dict, OrderedDict):
            errors.append(f'Expected self.dims_dict="{self.dims_dict}" to be OrderedDict')
        if errors:
            formatted_errors = '\n' + '\n'.join(errors)
            raise RuntimeError(f'Found errors in data members:{formatted_errors}')

TabTernary⚓︎

class TabTernary(
    app: Union[dash.dash.Dash, NoneType] = None
)
View Source
class TabTernary(TabBase):
    """TabTernary properties."""

    name = 'Ternary'
    data = px.data.election()
    func_map = OrderedDict([
        ('scatter_ternary', px.scatter_ternary),
        ('line_ternary', px.line_ternary),
    ])
    dims = ('a', 'b', 'c', 'color', 'hover_name')  # size - only for scatter
    default_dim_name = {
        'a': 'Joly',
        'b': 'Coderre',
        'c': 'Bergeron',
        'color': 'winner',
        'hover_name': 'district',
    }

Ancestors (in MRO)⚓︎

  • dash_charts.app_px.TabBase
  • dash_charts.utils_app.AppBase

Class variables⚓︎

data
default_dim_name
dims
dims_dict
external_stylesheets
func_map
id_chart
id_func
id_template
init_app_kwargs
modules
name
nsi
takes_args
templates
validation_layout

Methods⚓︎

callback⚓︎

def callback(
    self,
    outputs,
    inputs,
    states,
    pic: bool = False,
    **kwargs: dict
)

Return app callback decorator based on provided components.

Parameters:

Name Description
outputs list of tuples with app_id and property name
inputs list of tuples with app_id and property name
states list of tuples with app_id and property name
pic If True, prevent call on page load (prevent_initial_call). Default is False
**kwargs any additional keyword arguments for self.app.callback

Returns:

Type Description
dict result of self.app.callback()
View Source
    def callback(self, outputs, inputs, states, pic: bool = False, **kwargs: dict):
        """Return app callback decorator based on provided components.

        Args:
            outputs: list of tuples with app_id and property name
            inputs: list of tuples with app_id and property name
            states: list of tuples with app_id and property name
            pic: If True, prevent call on page load (`prevent_initial_call`). Default is False
            **kwargs: any additional keyword arguments for `self.app.callback`

        Returns:
            dict: result of `self.app.callback()`

        """
        return self.app.callback(
            *format_app_callback(self._il, outputs, inputs, states),
            prevent_initial_call=pic,
            **kwargs,
        )

create⚓︎

def create(
    self,
    assign_layout: bool = True
) -> None

Create the ids, app charts, layout, callbacks, and optional modules.

Parameters:

Name Description
assign_layout if True, will assign self.app.layout. If False, must call self.return_layout separately.
Default is True

Raises:

Type Description
NotImplementedError if child class has not set the self.name data member
View Source
    def create(self, assign_layout: bool = True) -> None:  # noqa: CCR001
        """Create the ids, app charts, layout, callbacks, and optional modules.

        Args:
            assign_layout: if True, will assign `self.app.layout`. If False, must call `self.return_layout` separately.
                Default is True

        Raises:
            NotImplementedError: if child class has not set the `self.name` data member

        """
        if self.name is None:  # pragma: no cover
            raise NotImplementedError('Child class must set `self.name` to a unique string for this app')

        # Initialize app and each module
        self.initialization()
        for mod in self.modules:
            self.register_uniq_ids(mod.all_ids)
        self.override_module_defaults()  # Call optional override method

        # Create charts for app and each module
        self.create_elements()
        for mod in self.modules:
            mod.create_elements(self._il)

        # Create app layout. User must call the return_layout method from each module within own return_layout method
        if assign_layout:
            self.app.layout = self.return_layout()
        if assign_layout and self.validation_layout:
            self.app.validation_layout = [deepcopy(self.app.layout)] + self.validation_layout
            pprint('\n\nValidationLayout?')
            pprint(self.app.validation_layout)

        # Create callbacks for app and each module
        self.create_callbacks()
        for mod in self.modules:
            mod.create_callbacks(self)

        self.verify_app_initialization()

create_callbacks⚓︎

def create_callbacks(
    self
) -> None

Register callbacks necessary for this tab.

View Source
    def create_callbacks(self) -> None:
        """Register callbacks necessary for this tab."""
        self.verify_types_for_callbacks()

        self.register_update_chart()

create_elements⚓︎

def create_elements(
    self
) -> None

Initialize the charts, tables, and other Dash elements.

View Source
    def create_elements(self) -> None:
        """Initialize the charts, tables, and other Dash elements."""
        ...

generate_data⚓︎

def generate_data(
    self
) -> None

Recommended method for generating data stored in memory. Called in initialization.

View Source
    def generate_data(self) -> None:
        """Recommended method for generating data stored in memory. Called in initialization."""
        ...

get_server⚓︎

def get_server(
    self
)

Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

Returns:

Type Description
dict the Flask server component of the Dash app
View Source
    def get_server(self):
        """Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

        Returns:
            dict: the Flask `server` component of the Dash app

        """
        return self.app.server

initialization⚓︎

def initialization(
    self
) -> None

Initialize ids with self.register_uniq_ids([...]) and other one-time actions.

View Source
    def initialization(self) -> None:
        """Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
        super().initialization()

        # Register the the unique element IDs
        self.input_ids = [self.id_func, self.id_template] + [*self.dims] + [*self.dims_dict.keys()]
        self.register_uniq_ids([self.id_chart] + self.input_ids)

        # Configure the options for the various dropdowns
        self.col_opts = [] if self.data is None else tuple(opts_dd(_c, _c) for _c in self.data.columns)
        self.func_opts = tuple(opts_dd(lbl, lbl) for lbl in self.func_map.keys())
        self.t_opts = tuple(opts_dd(template, template) for template in self.templates)

override_module_defaults⚓︎

def override_module_defaults(
    self
) -> None

Override default values from modules.

View Source
    def override_module_defaults(self) -> None:
        """Override default values from modules."""
        ...

register_uniq_ids⚓︎

def register_uniq_ids(
    self,
    app_ids: List[str]
) -> None

Register the app_ids to the corresponding global_id in the self._il lookup dictionary.

The app_ids must be unique within this App so that a layout can be created. This method registers self._il which are a list of globally unique ids (incorporating this App’s unique self.name) allowing for the child class of this base App to be resused multiple times within a tabbed or multi-page application without id-collision

Parameters:

Name Description
app_ids list of strings that are unique within this App
View Source
    def register_uniq_ids(self, app_ids: List[str]) -> None:
        """Register the `app_ids` to the corresponding global_id in the `self._il` lookup dictionary.

        The app_ids must be unique within this App so that a layout can be created. This method registers `self._il`
          which are a list of globally unique ids (incorporating this App's unique `self.name`) allowing for the child
          class of this base App to be resused multiple times within a tabbed or multi-page application without
          id-collision

        Args:
            app_ids: list of strings that are unique within this App

        """
        self._il = deepcopy(self._il)
        for app_id in app_ids:
            self._il[app_id] = f'{self.name}-{app_id}'.replace(' ', '-')

register_update_chart⚓︎

def register_update_chart(
    self
)

Register the update_chart callback.

View Source
    def register_update_chart(self):   # noqa: CCR001
        """Register the update_chart callback."""
        outputs = [(self.id_chart, 'figure')]
        inputs = [(_id, 'value') for _id in self.input_ids]
        states = ()

        @self.callback(outputs, inputs, states)
        def update_chart(*raw_args):
            a_in, _a_states = map_args(raw_args, inputs, states)
            name_func = a_in[self.id_func]['value']

            properties = [trigger['prop_id'] for trigger in dash.callback_context.triggered]
            new_chart = {}
            # If event is not a tab change, return the updated chart
            if 'tabs-select.value' not in properties:  # FIXME: replace tabs-select with actual keyname (?)
                if self.takes_args:
                    # Parse the arguments to generate a new plot
                    kwargs = {key: a_in[key]['value'] for key in self.input_ids[1:]}
                    new_chart = self.func_map[name_func](self.data, height=650, **kwargs)
                else:
                    new_chart = self.func_map[name_func]()
            # Example Mapping Output. Alternatively, just: `return [new_chart]`
            return map_outputs(outputs, [(self.id_chart, 'figure', new_chart)])

return_layout⚓︎

def return_layout(
    self
) -> dict

Return Dash application layout.

Returns:

Type Description
dict Dash HTML object
View Source
    def return_layout(self) -> dict:
        """Return Dash application layout.

        Returns:
            dict: Dash HTML object

        """
        self.verify_types_for_layout()

        return html.Div(
            [  # noqa: ECE001
                html.Div(
                    [
                        dropdown_group(
                            'Plot Type:', self._il[self.id_func],
                            self.func_opts, value=self.func_opts[0]['label'],
                        ),
                        dropdown_group(
                            'Template:', self._il[self.id_template],
                            self.t_opts, value=self.t_opts[0]['label'],
                        ),
                    ] + [
                        dropdown_group(
                            f'{dim}:', self._il[dim], self.col_opts,
                            value=self.default_dim_name.get(dim, None),
                        )
                        for dim in self.dims
                    ] + [
                        dropdown_group(f'{dim}:', self._il[dim], [opts_dd(item, item) for item in items])
                        for dim, items in self.dims_dict.items()
                    ], style={'width': '25%', 'float': 'left'},
                ),
                min_graph(id=self._il[self.id_chart], style={'width': '75%', 'display': 'inline-block'}),
            ], style={'padding': '15px'},
        )

run⚓︎

def run(
    self,
    **dash_kwargs: dict
) -> None

Launch the Dash server instance.

Parameters:

Name Description
**dash_kwargs keyword arguments for Dash.run_server()
View Source
    def run(self, **dash_kwargs: dict) -> None:
        """Launch the Dash server instance.

        Args:
            **dash_kwargs: keyword arguments for `Dash.run_server()`

        """
        self.app.run_server(**dash_kwargs)  # pragma: no cover

verify_app_initialization⚓︎

def verify_app_initialization(
    self
) -> None

Check that the app was properly initialized.

Raises:

Type Description
RuntimeError if child class has not called self.register_uniq_ids
View Source
    def verify_app_initialization(self) -> None:
        """Check that the app was properly initialized.

        Raises:
            RuntimeError: if child class has not called `self.register_uniq_ids`

        """
        if not self._il.keys():  # pragma: no cover
            raise RuntimeError('Child class must first call `self.register_uniq_ids(__)` before self.run()')

verify_types_for_callbacks⚓︎

def verify_types_for_callbacks(
    self
)

Verify data types of data members necessary for the callbacks of this tab.

Raises:

Type Description
RuntimeError if any relevant data members are of the wrong type
View Source
    def verify_types_for_callbacks(self):
        """Verify data types of data members necessary for the callbacks of this tab.

        Raises:
            RuntimeError: if any relevant data members are of the wrong type

        """
        errors = []
        if not isinstance(self.takes_args, bool):
            errors.append(f'Expected self.takes_args="{self.takes_args}" to be bool')
        if not (isinstance(self.data, pd.DataFrame) or self.data is None):
            errors.append(f'Expected self.data="{self.data}" to be pd.DataFrame or None')
        if not isinstance(self.func_map, OrderedDict):
            errors.append(f'Expected self.func_map="{self.func_map}" to be OrderedDict')
        if errors:
            formatted_errors = '\n' + '\n'.join(errors)
            raise RuntimeError(f'Found errors in data members:{formatted_errors}')

verify_types_for_layout⚓︎

def verify_types_for_layout(
    self
)

Verify data types of data members necessary for the layout of this tab.

Raises:

Type Description
RuntimeError if any relevant data members are of the wrong type
View Source
    def verify_types_for_layout(self):
        """Verify data types of data members necessary for the layout of this tab.

        Raises:
            RuntimeError: if any relevant data members are of the wrong type

        """
        errors = []
        if not isinstance(self.name, str):
            errors.append(f'Expected self.name="{self.name}" to be str')
        if not isinstance(self.dims, tuple):
            errors.append(f'Expected self.dims="{self.dims}" to be tuple')
        if not isinstance(self.dims_dict, OrderedDict):
            errors.append(f'Expected self.dims_dict="{self.dims_dict}" to be OrderedDict')
        if errors:
            formatted_errors = '\n' + '\n'.join(errors)
            raise RuntimeError(f'Found errors in data members:{formatted_errors}')

TabTip⚓︎

class TabTip(
    app: Union[dash.dash.Dash, NoneType] = None
)
View Source
class TabTip(TabBase):
    """TabTip properties."""

    name = 'Tip Data'
    data = px.data.tips()
    func_map = OrderedDict([
        ('scatter', px.scatter),
        ('density_contour', px.density_contour),
    ])
    dims = ('x', 'y', 'color', 'facet_row', 'facet_col')
    dims_dict = OrderedDict([
        ('marginal_x', ('histogram', 'rag', 'violin', 'box')),
        ('marginal_y', ('histogram', 'rag', 'violin', 'box')),
        ('trendline', ('ols', 'lowess')),
    ])
    default_dim_name = {
        'x': 'total_bill',
        'y': 'tip',
        'color': 'smoker',
    }

Ancestors (in MRO)⚓︎

  • dash_charts.app_px.TabBase
  • dash_charts.utils_app.AppBase

Class variables⚓︎

data
default_dim_name
dims
dims_dict
external_stylesheets
func_map
id_chart
id_func
id_template
init_app_kwargs
modules
name
nsi
takes_args
templates
validation_layout

Methods⚓︎

callback⚓︎

def callback(
    self,
    outputs,
    inputs,
    states,
    pic: bool = False,
    **kwargs: dict
)

Return app callback decorator based on provided components.

Parameters:

Name Description
outputs list of tuples with app_id and property name
inputs list of tuples with app_id and property name
states list of tuples with app_id and property name
pic If True, prevent call on page load (prevent_initial_call). Default is False
**kwargs any additional keyword arguments for self.app.callback

Returns:

Type Description
dict result of self.app.callback()
View Source
    def callback(self, outputs, inputs, states, pic: bool = False, **kwargs: dict):
        """Return app callback decorator based on provided components.

        Args:
            outputs: list of tuples with app_id and property name
            inputs: list of tuples with app_id and property name
            states: list of tuples with app_id and property name
            pic: If True, prevent call on page load (`prevent_initial_call`). Default is False
            **kwargs: any additional keyword arguments for `self.app.callback`

        Returns:
            dict: result of `self.app.callback()`

        """
        return self.app.callback(
            *format_app_callback(self._il, outputs, inputs, states),
            prevent_initial_call=pic,
            **kwargs,
        )

create⚓︎

def create(
    self,
    assign_layout: bool = True
) -> None

Create the ids, app charts, layout, callbacks, and optional modules.

Parameters:

Name Description
assign_layout if True, will assign self.app.layout. If False, must call self.return_layout separately.
Default is True

Raises:

Type Description
NotImplementedError if child class has not set the self.name data member
View Source
    def create(self, assign_layout: bool = True) -> None:  # noqa: CCR001
        """Create the ids, app charts, layout, callbacks, and optional modules.

        Args:
            assign_layout: if True, will assign `self.app.layout`. If False, must call `self.return_layout` separately.
                Default is True

        Raises:
            NotImplementedError: if child class has not set the `self.name` data member

        """
        if self.name is None:  # pragma: no cover
            raise NotImplementedError('Child class must set `self.name` to a unique string for this app')

        # Initialize app and each module
        self.initialization()
        for mod in self.modules:
            self.register_uniq_ids(mod.all_ids)
        self.override_module_defaults()  # Call optional override method

        # Create charts for app and each module
        self.create_elements()
        for mod in self.modules:
            mod.create_elements(self._il)

        # Create app layout. User must call the return_layout method from each module within own return_layout method
        if assign_layout:
            self.app.layout = self.return_layout()
        if assign_layout and self.validation_layout:
            self.app.validation_layout = [deepcopy(self.app.layout)] + self.validation_layout
            pprint('\n\nValidationLayout?')
            pprint(self.app.validation_layout)

        # Create callbacks for app and each module
        self.create_callbacks()
        for mod in self.modules:
            mod.create_callbacks(self)

        self.verify_app_initialization()

create_callbacks⚓︎

def create_callbacks(
    self
) -> None

Register callbacks necessary for this tab.

View Source
    def create_callbacks(self) -> None:
        """Register callbacks necessary for this tab."""
        self.verify_types_for_callbacks()

        self.register_update_chart()

create_elements⚓︎

def create_elements(
    self
) -> None

Initialize the charts, tables, and other Dash elements.

View Source
    def create_elements(self) -> None:
        """Initialize the charts, tables, and other Dash elements."""
        ...

generate_data⚓︎

def generate_data(
    self
) -> None

Recommended method for generating data stored in memory. Called in initialization.

View Source
    def generate_data(self) -> None:
        """Recommended method for generating data stored in memory. Called in initialization."""
        ...

get_server⚓︎

def get_server(
    self
)

Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

Returns:

Type Description
dict the Flask server component of the Dash app
View Source
    def get_server(self):
        """Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

        Returns:
            dict: the Flask `server` component of the Dash app

        """
        return self.app.server

initialization⚓︎

def initialization(
    self
) -> None

Initialize ids with self.register_uniq_ids([...]) and other one-time actions.

View Source
    def initialization(self) -> None:
        """Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
        super().initialization()

        # Register the the unique element IDs
        self.input_ids = [self.id_func, self.id_template] + [*self.dims] + [*self.dims_dict.keys()]
        self.register_uniq_ids([self.id_chart] + self.input_ids)

        # Configure the options for the various dropdowns
        self.col_opts = [] if self.data is None else tuple(opts_dd(_c, _c) for _c in self.data.columns)
        self.func_opts = tuple(opts_dd(lbl, lbl) for lbl in self.func_map.keys())
        self.t_opts = tuple(opts_dd(template, template) for template in self.templates)

override_module_defaults⚓︎

def override_module_defaults(
    self
) -> None

Override default values from modules.

View Source
    def override_module_defaults(self) -> None:
        """Override default values from modules."""
        ...

register_uniq_ids⚓︎

def register_uniq_ids(
    self,
    app_ids: List[str]
) -> None

Register the app_ids to the corresponding global_id in the self._il lookup dictionary.

The app_ids must be unique within this App so that a layout can be created. This method registers self._il which are a list of globally unique ids (incorporating this App’s unique self.name) allowing for the child class of this base App to be resused multiple times within a tabbed or multi-page application without id-collision

Parameters:

Name Description
app_ids list of strings that are unique within this App
View Source
    def register_uniq_ids(self, app_ids: List[str]) -> None:
        """Register the `app_ids` to the corresponding global_id in the `self._il` lookup dictionary.

        The app_ids must be unique within this App so that a layout can be created. This method registers `self._il`
          which are a list of globally unique ids (incorporating this App's unique `self.name`) allowing for the child
          class of this base App to be resused multiple times within a tabbed or multi-page application without
          id-collision

        Args:
            app_ids: list of strings that are unique within this App

        """
        self._il = deepcopy(self._il)
        for app_id in app_ids:
            self._il[app_id] = f'{self.name}-{app_id}'.replace(' ', '-')

register_update_chart⚓︎

def register_update_chart(
    self
)

Register the update_chart callback.

View Source
    def register_update_chart(self):   # noqa: CCR001
        """Register the update_chart callback."""
        outputs = [(self.id_chart, 'figure')]
        inputs = [(_id, 'value') for _id in self.input_ids]
        states = ()

        @self.callback(outputs, inputs, states)
        def update_chart(*raw_args):
            a_in, _a_states = map_args(raw_args, inputs, states)
            name_func = a_in[self.id_func]['value']

            properties = [trigger['prop_id'] for trigger in dash.callback_context.triggered]
            new_chart = {}
            # If event is not a tab change, return the updated chart
            if 'tabs-select.value' not in properties:  # FIXME: replace tabs-select with actual keyname (?)
                if self.takes_args:
                    # Parse the arguments to generate a new plot
                    kwargs = {key: a_in[key]['value'] for key in self.input_ids[1:]}
                    new_chart = self.func_map[name_func](self.data, height=650, **kwargs)
                else:
                    new_chart = self.func_map[name_func]()
            # Example Mapping Output. Alternatively, just: `return [new_chart]`
            return map_outputs(outputs, [(self.id_chart, 'figure', new_chart)])

return_layout⚓︎

def return_layout(
    self
) -> dict

Return Dash application layout.

Returns:

Type Description
dict Dash HTML object
View Source
    def return_layout(self) -> dict:
        """Return Dash application layout.

        Returns:
            dict: Dash HTML object

        """
        self.verify_types_for_layout()

        return html.Div(
            [  # noqa: ECE001
                html.Div(
                    [
                        dropdown_group(
                            'Plot Type:', self._il[self.id_func],
                            self.func_opts, value=self.func_opts[0]['label'],
                        ),
                        dropdown_group(
                            'Template:', self._il[self.id_template],
                            self.t_opts, value=self.t_opts[0]['label'],
                        ),
                    ] + [
                        dropdown_group(
                            f'{dim}:', self._il[dim], self.col_opts,
                            value=self.default_dim_name.get(dim, None),
                        )
                        for dim in self.dims
                    ] + [
                        dropdown_group(f'{dim}:', self._il[dim], [opts_dd(item, item) for item in items])
                        for dim, items in self.dims_dict.items()
                    ], style={'width': '25%', 'float': 'left'},
                ),
                min_graph(id=self._il[self.id_chart], style={'width': '75%', 'display': 'inline-block'}),
            ], style={'padding': '15px'},
        )

run⚓︎

def run(
    self,
    **dash_kwargs: dict
) -> None

Launch the Dash server instance.

Parameters:

Name Description
**dash_kwargs keyword arguments for Dash.run_server()
View Source
    def run(self, **dash_kwargs: dict) -> None:
        """Launch the Dash server instance.

        Args:
            **dash_kwargs: keyword arguments for `Dash.run_server()`

        """
        self.app.run_server(**dash_kwargs)  # pragma: no cover

verify_app_initialization⚓︎

def verify_app_initialization(
    self
) -> None

Check that the app was properly initialized.

Raises:

Type Description
RuntimeError if child class has not called self.register_uniq_ids
View Source
    def verify_app_initialization(self) -> None:
        """Check that the app was properly initialized.

        Raises:
            RuntimeError: if child class has not called `self.register_uniq_ids`

        """
        if not self._il.keys():  # pragma: no cover
            raise RuntimeError('Child class must first call `self.register_uniq_ids(__)` before self.run()')

verify_types_for_callbacks⚓︎

def verify_types_for_callbacks(
    self
)

Verify data types of data members necessary for the callbacks of this tab.

Raises:

Type Description
RuntimeError if any relevant data members are of the wrong type
View Source
    def verify_types_for_callbacks(self):
        """Verify data types of data members necessary for the callbacks of this tab.

        Raises:
            RuntimeError: if any relevant data members are of the wrong type

        """
        errors = []
        if not isinstance(self.takes_args, bool):
            errors.append(f'Expected self.takes_args="{self.takes_args}" to be bool')
        if not (isinstance(self.data, pd.DataFrame) or self.data is None):
            errors.append(f'Expected self.data="{self.data}" to be pd.DataFrame or None')
        if not isinstance(self.func_map, OrderedDict):
            errors.append(f'Expected self.func_map="{self.func_map}" to be OrderedDict')
        if errors:
            formatted_errors = '\n' + '\n'.join(errors)
            raise RuntimeError(f'Found errors in data members:{formatted_errors}')

verify_types_for_layout⚓︎

def verify_types_for_layout(
    self
)

Verify data types of data members necessary for the layout of this tab.

Raises:

Type Description
RuntimeError if any relevant data members are of the wrong type
View Source
    def verify_types_for_layout(self):
        """Verify data types of data members necessary for the layout of this tab.

        Raises:
            RuntimeError: if any relevant data members are of the wrong type

        """
        errors = []
        if not isinstance(self.name, str):
            errors.append(f'Expected self.name="{self.name}" to be str')
        if not isinstance(self.dims, tuple):
            errors.append(f'Expected self.dims="{self.dims}" to be tuple')
        if not isinstance(self.dims_dict, OrderedDict):
            errors.append(f'Expected self.dims_dict="{self.dims_dict}" to be OrderedDict')
        if errors:
            formatted_errors = '\n' + '\n'.join(errors)
            raise RuntimeError(f'Found errors in data members:{formatted_errors}')

TabWind⚓︎

class TabWind(
    app: Union[dash.dash.Dash, NoneType] = None
)
View Source
class TabWind(TabBase):
    """TabWind properties."""

    name = 'Wind'
    data = px.data.wind()
    func_map = OrderedDict([
        ('scatter_polar', px.scatter_polar),
        ('line_polar', px.line_polar),  # (line_close=True)
        ('bar_polar', px.bar_polar),
    ])
    dims = ('r', 'theta', 'color')
    default_dim_name = {
        'r': 'frequency',
        'theta': 'direction',
        'color': 'strength',
        'symbol': 'strength',
    }

Ancestors (in MRO)⚓︎

  • dash_charts.app_px.TabBase
  • dash_charts.utils_app.AppBase

Class variables⚓︎

data
default_dim_name
dims
dims_dict
external_stylesheets
func_map
id_chart
id_func
id_template
init_app_kwargs
modules
name
nsi
takes_args
templates
validation_layout

Methods⚓︎

callback⚓︎

def callback(
    self,
    outputs,
    inputs,
    states,
    pic: bool = False,
    **kwargs: dict
)

Return app callback decorator based on provided components.

Parameters:

Name Description
outputs list of tuples with app_id and property name
inputs list of tuples with app_id and property name
states list of tuples with app_id and property name
pic If True, prevent call on page load (prevent_initial_call). Default is False
**kwargs any additional keyword arguments for self.app.callback

Returns:

Type Description
dict result of self.app.callback()
View Source
    def callback(self, outputs, inputs, states, pic: bool = False, **kwargs: dict):
        """Return app callback decorator based on provided components.

        Args:
            outputs: list of tuples with app_id and property name
            inputs: list of tuples with app_id and property name
            states: list of tuples with app_id and property name
            pic: If True, prevent call on page load (`prevent_initial_call`). Default is False
            **kwargs: any additional keyword arguments for `self.app.callback`

        Returns:
            dict: result of `self.app.callback()`

        """
        return self.app.callback(
            *format_app_callback(self._il, outputs, inputs, states),
            prevent_initial_call=pic,
            **kwargs,
        )

create⚓︎

def create(
    self,
    assign_layout: bool = True
) -> None

Create the ids, app charts, layout, callbacks, and optional modules.

Parameters:

Name Description
assign_layout if True, will assign self.app.layout. If False, must call self.return_layout separately.
Default is True

Raises:

Type Description
NotImplementedError if child class has not set the self.name data member
View Source
    def create(self, assign_layout: bool = True) -> None:  # noqa: CCR001
        """Create the ids, app charts, layout, callbacks, and optional modules.

        Args:
            assign_layout: if True, will assign `self.app.layout`. If False, must call `self.return_layout` separately.
                Default is True

        Raises:
            NotImplementedError: if child class has not set the `self.name` data member

        """
        if self.name is None:  # pragma: no cover
            raise NotImplementedError('Child class must set `self.name` to a unique string for this app')

        # Initialize app and each module
        self.initialization()
        for mod in self.modules:
            self.register_uniq_ids(mod.all_ids)
        self.override_module_defaults()  # Call optional override method

        # Create charts for app and each module
        self.create_elements()
        for mod in self.modules:
            mod.create_elements(self._il)

        # Create app layout. User must call the return_layout method from each module within own return_layout method
        if assign_layout:
            self.app.layout = self.return_layout()
        if assign_layout and self.validation_layout:
            self.app.validation_layout = [deepcopy(self.app.layout)] + self.validation_layout
            pprint('\n\nValidationLayout?')
            pprint(self.app.validation_layout)

        # Create callbacks for app and each module
        self.create_callbacks()
        for mod in self.modules:
            mod.create_callbacks(self)

        self.verify_app_initialization()

create_callbacks⚓︎

def create_callbacks(
    self
) -> None

Register callbacks necessary for this tab.

View Source
    def create_callbacks(self) -> None:
        """Register callbacks necessary for this tab."""
        self.verify_types_for_callbacks()

        self.register_update_chart()

create_elements⚓︎

def create_elements(
    self
) -> None

Initialize the charts, tables, and other Dash elements.

View Source
    def create_elements(self) -> None:
        """Initialize the charts, tables, and other Dash elements."""
        ...

generate_data⚓︎

def generate_data(
    self
) -> None

Recommended method for generating data stored in memory. Called in initialization.

View Source
    def generate_data(self) -> None:
        """Recommended method for generating data stored in memory. Called in initialization."""
        ...

get_server⚓︎

def get_server(
    self
)

Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

Returns:

Type Description
dict the Flask server component of the Dash app
View Source
    def get_server(self):
        """Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

        Returns:
            dict: the Flask `server` component of the Dash app

        """
        return self.app.server

initialization⚓︎

def initialization(
    self
) -> None

Initialize ids with self.register_uniq_ids([...]) and other one-time actions.

View Source
    def initialization(self) -> None:
        """Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
        super().initialization()

        # Register the the unique element IDs
        self.input_ids = [self.id_func, self.id_template] + [*self.dims] + [*self.dims_dict.keys()]
        self.register_uniq_ids([self.id_chart] + self.input_ids)

        # Configure the options for the various dropdowns
        self.col_opts = [] if self.data is None else tuple(opts_dd(_c, _c) for _c in self.data.columns)
        self.func_opts = tuple(opts_dd(lbl, lbl) for lbl in self.func_map.keys())
        self.t_opts = tuple(opts_dd(template, template) for template in self.templates)

override_module_defaults⚓︎

def override_module_defaults(
    self
) -> None

Override default values from modules.

View Source
    def override_module_defaults(self) -> None:
        """Override default values from modules."""
        ...

register_uniq_ids⚓︎

def register_uniq_ids(
    self,
    app_ids: List[str]
) -> None

Register the app_ids to the corresponding global_id in the self._il lookup dictionary.

The app_ids must be unique within this App so that a layout can be created. This method registers self._il which are a list of globally unique ids (incorporating this App’s unique self.name) allowing for the child class of this base App to be resused multiple times within a tabbed or multi-page application without id-collision

Parameters:

Name Description
app_ids list of strings that are unique within this App
View Source
    def register_uniq_ids(self, app_ids: List[str]) -> None:
        """Register the `app_ids` to the corresponding global_id in the `self._il` lookup dictionary.

        The app_ids must be unique within this App so that a layout can be created. This method registers `self._il`
          which are a list of globally unique ids (incorporating this App's unique `self.name`) allowing for the child
          class of this base App to be resused multiple times within a tabbed or multi-page application without
          id-collision

        Args:
            app_ids: list of strings that are unique within this App

        """
        self._il = deepcopy(self._il)
        for app_id in app_ids:
            self._il[app_id] = f'{self.name}-{app_id}'.replace(' ', '-')

register_update_chart⚓︎

def register_update_chart(
    self
)

Register the update_chart callback.

View Source
    def register_update_chart(self):   # noqa: CCR001
        """Register the update_chart callback."""
        outputs = [(self.id_chart, 'figure')]
        inputs = [(_id, 'value') for _id in self.input_ids]
        states = ()

        @self.callback(outputs, inputs, states)
        def update_chart(*raw_args):
            a_in, _a_states = map_args(raw_args, inputs, states)
            name_func = a_in[self.id_func]['value']

            properties = [trigger['prop_id'] for trigger in dash.callback_context.triggered]
            new_chart = {}
            # If event is not a tab change, return the updated chart
            if 'tabs-select.value' not in properties:  # FIXME: replace tabs-select with actual keyname (?)
                if self.takes_args:
                    # Parse the arguments to generate a new plot
                    kwargs = {key: a_in[key]['value'] for key in self.input_ids[1:]}
                    new_chart = self.func_map[name_func](self.data, height=650, **kwargs)
                else:
                    new_chart = self.func_map[name_func]()
            # Example Mapping Output. Alternatively, just: `return [new_chart]`
            return map_outputs(outputs, [(self.id_chart, 'figure', new_chart)])

return_layout⚓︎

def return_layout(
    self
) -> dict

Return Dash application layout.

Returns:

Type Description
dict Dash HTML object
View Source
    def return_layout(self) -> dict:
        """Return Dash application layout.

        Returns:
            dict: Dash HTML object

        """
        self.verify_types_for_layout()

        return html.Div(
            [  # noqa: ECE001
                html.Div(
                    [
                        dropdown_group(
                            'Plot Type:', self._il[self.id_func],
                            self.func_opts, value=self.func_opts[0]['label'],
                        ),
                        dropdown_group(
                            'Template:', self._il[self.id_template],
                            self.t_opts, value=self.t_opts[0]['label'],
                        ),
                    ] + [
                        dropdown_group(
                            f'{dim}:', self._il[dim], self.col_opts,
                            value=self.default_dim_name.get(dim, None),
                        )
                        for dim in self.dims
                    ] + [
                        dropdown_group(f'{dim}:', self._il[dim], [opts_dd(item, item) for item in items])
                        for dim, items in self.dims_dict.items()
                    ], style={'width': '25%', 'float': 'left'},
                ),
                min_graph(id=self._il[self.id_chart], style={'width': '75%', 'display': 'inline-block'}),
            ], style={'padding': '15px'},
        )

run⚓︎

def run(
    self,
    **dash_kwargs: dict
) -> None

Launch the Dash server instance.

Parameters:

Name Description
**dash_kwargs keyword arguments for Dash.run_server()
View Source
    def run(self, **dash_kwargs: dict) -> None:
        """Launch the Dash server instance.

        Args:
            **dash_kwargs: keyword arguments for `Dash.run_server()`

        """
        self.app.run_server(**dash_kwargs)  # pragma: no cover

verify_app_initialization⚓︎

def verify_app_initialization(
    self
) -> None

Check that the app was properly initialized.

Raises:

Type Description
RuntimeError if child class has not called self.register_uniq_ids
View Source
    def verify_app_initialization(self) -> None:
        """Check that the app was properly initialized.

        Raises:
            RuntimeError: if child class has not called `self.register_uniq_ids`

        """
        if not self._il.keys():  # pragma: no cover
            raise RuntimeError('Child class must first call `self.register_uniq_ids(__)` before self.run()')

verify_types_for_callbacks⚓︎

def verify_types_for_callbacks(
    self
)

Verify data types of data members necessary for the callbacks of this tab.

Raises:

Type Description
RuntimeError if any relevant data members are of the wrong type
View Source
    def verify_types_for_callbacks(self):
        """Verify data types of data members necessary for the callbacks of this tab.

        Raises:
            RuntimeError: if any relevant data members are of the wrong type

        """
        errors = []
        if not isinstance(self.takes_args, bool):
            errors.append(f'Expected self.takes_args="{self.takes_args}" to be bool')
        if not (isinstance(self.data, pd.DataFrame) or self.data is None):
            errors.append(f'Expected self.data="{self.data}" to be pd.DataFrame or None')
        if not isinstance(self.func_map, OrderedDict):
            errors.append(f'Expected self.func_map="{self.func_map}" to be OrderedDict')
        if errors:
            formatted_errors = '\n' + '\n'.join(errors)
            raise RuntimeError(f'Found errors in data members:{formatted_errors}')

verify_types_for_layout⚓︎

def verify_types_for_layout(
    self
)

Verify data types of data members necessary for the layout of this tab.

Raises:

Type Description
RuntimeError if any relevant data members are of the wrong type
View Source
    def verify_types_for_layout(self):
        """Verify data types of data members necessary for the layout of this tab.

        Raises:
            RuntimeError: if any relevant data members are of the wrong type

        """
        errors = []
        if not isinstance(self.name, str):
            errors.append(f'Expected self.name="{self.name}" to be str')
        if not isinstance(self.dims, tuple):
            errors.append(f'Expected self.dims="{self.dims}" to be tuple')
        if not isinstance(self.dims_dict, OrderedDict):
            errors.append(f'Expected self.dims_dict="{self.dims_dict}" to be OrderedDict')
        if errors:
            formatted_errors = '\n' + '\n'.join(errors)
            raise RuntimeError(f'Found errors in data members:{formatted_errors}')

Last update: August 5, 2022
Created: August 5, 2022